refactor language handling

Because Qt translations need to be initialized before any widgets are created,
and because the Qt language needs to match the gettext language in order for
translated shortcuts to work, per-profile language settings aren't possible.
So instead of storing the language in the profile, we use
pm.meta['defaultLang'] for all profiles and initialize language handling in
__init__.py

The language selection in the preferences has been removed, because in a
school setting a student fiddling with the language could potentially cause
other students to be unable to navigate the UI. Instead, Anki will accept
-l/--lang passed on the command line to override the original language chosen
at first program startup.
This commit is contained in:
Damien Elmes 2012-04-18 03:06:38 +09:00
parent dbc004e0ef
commit d919615475
5 changed files with 46 additions and 115 deletions

View file

@ -1,8 +1,10 @@
# Copyright: Damien Elmes <anki@ichi2.net>
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import os, sys
import os, sys, __builtin__
from aqt.qt import *
import locale, gettext
import anki.lang
appVersion="2.0-beta3"
appWebsite="http://ankisrs.net/"
@ -49,6 +51,44 @@ class DialogManager(object):
dialogs = DialogManager()
# Language handling
##########################################################################
# Qt requires its translator to be installed before any GUI widgets are
# loaded, and we need the Qt language to match the gettext language or
# translated shortcuts will not work.
_gtrans = None
_qtrans = None
def langDir():
dir = os.path.join(moduleDir, "aqt", "locale")
if not os.path.exists(dir):
dir = os.path.join(os.path.dirname(sys.argv[0]), "locale")
return dir
def setupLang(pm, app, force=None):
global _gtrans, _qtrans
try:
locale.setlocale(locale.LC_ALL, '')
except:
pass
lang = force or pm.meta["defaultLang"]
dir = langDir()
# gettext
_gtrans = gettext.translation(
'ankiqt', dir, languages=[lang], fallback=True)
__builtin__.__dict__['_'] = _gtrans.ugettext
__builtin__.__dict__['ngettext'] = _gtrans.ungettext
anki.lang.setLang(lang, local=False)
if lang in ("he","ar","fa"):
app.setLayoutDirection(Qt.RightToLeft)
else:
app.setLayoutDirection(Qt.LeftToRight)
# qt
_qtrans = QTranslator()
if _qtrans.load("qt_" + lang, dir):
app.installTranslator(_qtrans)
# App initialisation
##########################################################################
@ -80,20 +120,15 @@ def run():
parser.usage = "%prog [OPTIONS]"
parser.add_option("-b", "--base", help="Path to base folder")
parser.add_option("-p", "--profile", help="Profile name to load")
parser.add_option("-l", "--lang", help="Interface language (en, de, etc)")
(opts, args) = parser.parse_args(sys.argv[1:])
# profile manager
from aqt.profiles import ProfileManager
pm = ProfileManager(opts.base, opts.profile)
# qt translations
qtTranslator = QTranslator()
languageDir = os.path.join(moduleDir, "aqt", "locale")
if not os.path.exists(languageDir):
languageDir = os.path.join(
os.path.dirname(sys.argv[0]), "locale")
if qtTranslator.load("qt_" + pm.meta['defaultLang'], languageDir):
app.installTranslator(qtTranslator)
# i18n
setupLang(pm, app, opts.lang)
import aqt.main
mw = aqt.main.AnkiQt(app, pm)

View file

@ -21,20 +21,12 @@ from aqt.utils import saveGeom, restoreGeom, showInfo, showWarning, \
askUserDialog, applyStyles, getText, showText, showCritical, getFile, \
tooltip, openHelp, openLink
## fixme: open plugin folder broken on win32?
## models remembering the previous group
class AnkiQt(QMainWindow):
def __init__(self, app, profileManager):
QMainWindow.__init__(self)
aqt.mw = self
self.app = app
self.pm = profileManager
# use the global language for early init; once a profile or the
# profile manager is loaded we can switch to a user's preferred
# language
self.setupLang(force=self.pm.meta['defaultLang'])
# running 2.0 for the first time?
if self.pm.meta['firstRun']:
# load the new deck user profile
@ -100,7 +92,6 @@ class AnkiQt(QMainWindow):
self.loadProfile()
def showProfileManager(self):
self.setupLang(force=self.pm.meta['defaultLang'])
d = self.profileDiag = QDialog()
f = self.profileForm = aqt.forms.profiles.Ui_Dialog()
f.setupUi(d)
@ -191,7 +182,6 @@ Are you sure?"""):
self.refreshProfilesList()
def loadProfile(self):
self.setupLang()
# show main window
if self.pm.profile['mainWindowState']:
restoreGeom(self, "mainWindow")
@ -755,45 +745,6 @@ upload, overwriting any changes either here or on AnkiWeb. Proceed?""")):
else:
self.moveToState("overview")
# Language handling
##########################################################################
def setupLang(self, force=None):
"Set the user interface language for the current profile."
import locale, gettext
import anki.lang
try:
locale.setlocale(locale.LC_ALL, '')
except:
pass
lang = force if force else self.pm.profile["lang"]
languageDir=os.path.join(aqt.moduleDir, "aqt", "locale")
if not os.path.exists(languageDir):
languageDir = os.path.join(
os.path.dirname(sys.argv[0]), "locale")
self.languageTrans = gettext.translation('ankiqt', languageDir,
languages=[lang],
fallback=True)
self.installTranslation()
if getattr(self, 'form', None):
self.form.retranslateUi(self)
anki.lang.setLang(lang, local=False)
if lang in ("he","ar","fa"):
self.app.setLayoutDirection(Qt.RightToLeft)
else:
self.app.setLayoutDirection(Qt.LeftToRight)
def getTranslation(self, text):
return self.languageTrans.ugettext(text)
def getTranslation2(self, text1, text2, n):
return self.languageTrans.ungettext(text1, text2, n)
def installTranslation(self):
import __builtin__
__builtin__.__dict__['_'] = self.getTranslation
__builtin__.__dict__['ngettext'] = self.getTranslation2
# Menu, title bar & status
##########################################################################

View file

@ -4,7 +4,6 @@
import datetime, time, os
from aqt.qt import *
from anki.lang import langs
from aqt.utils import openFolder, showWarning, getText, openHelp
import aqt
@ -19,7 +18,6 @@ class Preferences(QDialog):
self.connect(self.form.buttonBox, SIGNAL("helpRequested()"),
lambda: openHelp("profileprefs"))
self.setupCollection()
self.setupLang()
self.setupNetwork()
self.setupBackup()
self.setupOptions()
@ -69,35 +67,6 @@ class Preferences(QDialog):
d.crt = int(time.mktime(date.timetuple()))
d.setMod()
# Language handling
######################################################################
def setupLang(self):
# interface lang
for (lang, code) in langs:
self.form.interfaceLang.addItem(lang)
self.form.interfaceLang.setCurrentIndex(
self.codeToIndex(self.prof['lang']))
self.connect(self.form.interfaceLang,
SIGNAL("currentIndexChanged(QString)"),
self.interfaceLangChanged)
def codeToIndex(self, code):
n = 0
for (lang, type) in langs:
if code == type:
return n
n += 1
# default to english
return self.codeToIndex("en")
def interfaceLangChanged(self):
self.prof['lang'] = (
langs[self.form.interfaceLang.currentIndex()])[1]
self.mw.setupLang()
self.form.retranslateUi(self)
# Network
######################################################################

View file

@ -33,7 +33,6 @@ profileConf = dict(
mainWindowState=None,
numBackups=30,
lastOptimize=intTime(),
lang="en",
# editing
fullSearch=False,
@ -142,7 +141,6 @@ computer.""")
def create(self, name):
prof = profileConf.copy()
prof['lang'] = self.meta['defaultLang']
self.db.execute("insert into profiles values (?, ?)",
name, cPickle.dumps(prof))
self.db.commit()

View file

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>439</width>
<height>420</height>
<width>441</width>
<height>426</height>
</rect>
</property>
<property name="windowTitle">
@ -30,27 +30,6 @@
<property name="spacing">
<number>12</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Language:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="interfaceLang">
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="showEstimates">
<property name="text">
@ -483,7 +462,6 @@
</layout>
</widget>
<tabstops>
<tabstop>interfaceLang</tabstop>
<tabstop>showEstimates</tabstop>
<tabstop>showProgress</tabstop>
<tabstop>stripHTML</tabstop>