Merge pull request #680 from bkmeneguello/Languages-GUI
Adds language selector to preferences
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
*.egg-info
|
||||
setup.iss
|
||||
novelwriter.desktop
|
||||
i18n/*.qm
|
||||
i18n/*.qph
|
||||
|
||||
# Documentation
|
||||
/docs/build/
|
||||
|
||||
Binary file not shown.
@@ -1,447 +0,0 @@
|
||||
<!DOCTYPE QPH>
|
||||
<QPH sourcelanguage="en" language="pt">
|
||||
<phrase>
|
||||
<source>Point of View</source>
|
||||
<target>Ponto de Vista</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Characters</source>
|
||||
<target>Personagens</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Plot</source>
|
||||
<target>Enredo</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Timeline</source>
|
||||
<target>Linha do Tempo</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Locations</source>
|
||||
<target>Lugares</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Objects</source>
|
||||
<target>Objetos</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Entities</source>
|
||||
<target>Entidades</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>None</source>
|
||||
<target>Nenhum</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Novel</source>
|
||||
<target>Livro</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Entity</source>
|
||||
<target>Entidade</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Outtakes</source>
|
||||
<target>Removidos</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Trash</source>
|
||||
<target>Lixeira</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Title Page</source>
|
||||
<target>Página de Título</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Book</source>
|
||||
<target>Livro</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Plain Page</source>
|
||||
<target>Página</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Partition</source>
|
||||
<target>Partição</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Unnumbered</source>
|
||||
<target>Sem Numeração</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Scene</source>
|
||||
<target>Cena</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Note</source>
|
||||
<target>Nota</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Title</source>
|
||||
<target>Título</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Level</source>
|
||||
<target>Nível</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Document</source>
|
||||
<target>Documento</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Line</source>
|
||||
<target>Linha</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Chars</source>
|
||||
<target>Caracteres</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Words</source>
|
||||
<target>Palavras</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Synopsis</source>
|
||||
<target>Sinopse</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>About</source>
|
||||
<target>Sobre</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Release</source>
|
||||
<target>Versões</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>About novelWriter</source>
|
||||
<target>Sobre o novelWriter</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Credits</source>
|
||||
<target>Créditos</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Author</source>
|
||||
<target>Autor</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Credit</source>
|
||||
<target>Créditos</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>License</source>
|
||||
<target>Licença</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Theme</source>
|
||||
<target>Tema</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Icons</source>
|
||||
<target>Ícones</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Syntax</source>
|
||||
<target>Sintaxe</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Website</source>
|
||||
<target>Website</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Chapter</source>
|
||||
<target>Capítulo</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Section</source>
|
||||
<target>Seção</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Font family</source>
|
||||
<target>Família da fonte</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Font size</source>
|
||||
<target>Tamanho da fonte</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Justify text</source>
|
||||
<target>Texto justificado</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Print</source>
|
||||
<target>Imprimir</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Build Project</source>
|
||||
<target>Construir o Projeto</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Save As</source>
|
||||
<target>Salvar Como</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Close</source>
|
||||
<target>Fechar</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Plain Text</source>
|
||||
<target>Texto Simples</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Plain HTML</source>
|
||||
<target>HTML Simples</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Save Document As</source>
|
||||
<target>Salvar Documento Como</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Unknown</source>
|
||||
<target>Desconhecido</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Look and Feel</source>
|
||||
<target>Aparência</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Project Backup</source>
|
||||
<target>Cópia de Segurança</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Path</source>
|
||||
<target>Caminho</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Status</source>
|
||||
<target>Estado</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Replace</source>
|
||||
<target>Substituir</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Search</source>
|
||||
<target>Pesquisa</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Handle</source>
|
||||
<target>Referência</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>References</source>
|
||||
<target>Referências</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Label</source>
|
||||
<target>Rótulo</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Class</source>
|
||||
<target>Classe</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Layout</source>
|
||||
<target>Leiaute</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source> Characters</source>
|
||||
<target>Caracteres</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Editor</source>
|
||||
<target>Editor</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Project</source>
|
||||
<target>Projeto</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Provider</source>
|
||||
<target>Provedor</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>unknown</source>
|
||||
<target>desconhecido</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Paragraphs</source>
|
||||
<target>Parágrafos</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Default</source>
|
||||
<target>Padrão</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Working title</source>
|
||||
<target>Nome do projeto</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Project path</source>
|
||||
<target>Caminho do projeto</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Project Stats</source>
|
||||
<target>Estatíticas do Projeto</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Folders</source>
|
||||
<target>Diretórios</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Documents</source>
|
||||
<target>Documentos</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Word count</source>
|
||||
<target>Contagem de palavras</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Keyword</source>
|
||||
<target>Palavra-chave</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>New</source>
|
||||
<target>Novo</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Delete</source>
|
||||
<target>Remover</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Save</source>
|
||||
<target>Salvar</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Name</source>
|
||||
<target>Nome</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>New Item</source>
|
||||
<target>Novo Item</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Last Opened</source>
|
||||
<target>Aberto Pela Última Vez</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Settings</source>
|
||||
<target>Configurações</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Details</source>
|
||||
<target>Detalhes</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Importance</source>
|
||||
<target>Importância</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Auto-Replace</source>
|
||||
<target>Substituir automaticamente</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Flag</source>
|
||||
<target>Opção</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Flags</source>
|
||||
<target>Opções</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>(New Entry)</source>
|
||||
<target></target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>New File</source>
|
||||
<target>Novo Arquivo</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>New Folder</source>
|
||||
<target>Novo Diretório</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Histogram</source>
|
||||
<target>Histograma</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Finished</source>
|
||||
<target>Finalizado</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Done</source>
|
||||
<target>Pronto</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Finish</source>
|
||||
<target>Terminar</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Auto-Replace</source>
|
||||
<target>Substituição Automática</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>No Suggestions</source>
|
||||
<target>Sem Sugestões</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Browse</source>
|
||||
<target>Procurar</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Tag</source>
|
||||
<target>Etiqueta</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Draft</source>
|
||||
<target>Rascunho</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Minor</source>
|
||||
<target>Menor</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Major</source>
|
||||
<target>Maior</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Backup</source>
|
||||
<target>Cópia de Segurança</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Undo</source>
|
||||
<target>Desfazer</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Release</source>
|
||||
<target>Lançamento</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Pages</source>
|
||||
<target>Páginas</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Page</source>
|
||||
<target>Página</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Progress</source>
|
||||
<target>Progresso</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Chapters</source>
|
||||
<target>Capítulos</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Scenes</source>
|
||||
<target>Cenas</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>Revisions</source>
|
||||
<target>Revisões</target>
|
||||
</phrase>
|
||||
<phrase>
|
||||
<source>seconds</source>
|
||||
<target>segundos</target>
|
||||
</phrase>
|
||||
</QPH>
|
||||
@@ -393,6 +393,25 @@ class Config:
|
||||
|
||||
return
|
||||
|
||||
def listLanguages(self):
|
||||
"""List localisation files in the i18n folder. The default GUI
|
||||
language 'en_GB' is British English.
|
||||
"""
|
||||
langList = {
|
||||
"en_GB": QLocale("en_GB").nativeLanguageName().title()
|
||||
}
|
||||
for qmFile in os.listdir(self.nwLangPath):
|
||||
if not os.path.isfile(os.path.join(self.nwLangPath, qmFile)):
|
||||
continue
|
||||
if not qmFile.startswith("nw_") or not qmFile.endswith(".qm"):
|
||||
continue
|
||||
qmLang = qmFile[3:-3]
|
||||
qmName = QLocale(qmLang).nativeLanguageName().title()
|
||||
if qmLang and qmName:
|
||||
langList[qmLang] = qmName
|
||||
|
||||
return sorted(langList.items(), key=lambda x: x[0])
|
||||
|
||||
def loadConfig(self):
|
||||
"""Load preferences from file and replace default settings.
|
||||
"""
|
||||
|
||||
+22
-2
@@ -137,10 +137,27 @@ class GuiPreferencesGeneral(QWidget):
|
||||
# Look and Feel
|
||||
# =============
|
||||
self.mainForm.addGroupLabel(self.tr("Look and Feel"))
|
||||
minWidth = self.mainConf.pxInt(200)
|
||||
|
||||
## Select Locale
|
||||
self.guiLang = QComboBox()
|
||||
self.guiLang.setMinimumWidth(minWidth)
|
||||
self.theLangs = self.mainConf.listLanguages()
|
||||
for lang, langName in self.theLangs:
|
||||
self.guiLang.addItem(langName, lang)
|
||||
langIdx = self.guiLang.findData(self.mainConf.guiLang)
|
||||
if langIdx != -1:
|
||||
self.guiLang.setCurrentIndex(langIdx)
|
||||
|
||||
self.mainForm.addRow(
|
||||
self.tr("Main GUI language"),
|
||||
self.guiLang,
|
||||
self.tr("Changing this requires restarting novelWriter.")
|
||||
)
|
||||
|
||||
## Select Theme
|
||||
self.guiTheme = QComboBox()
|
||||
self.guiTheme.setMinimumWidth(self.mainConf.pxInt(200))
|
||||
self.guiTheme.setMinimumWidth(minWidth)
|
||||
self.theThemes = self.theTheme.listThemes()
|
||||
for themeDir, themeName in self.theThemes:
|
||||
self.guiTheme.addItem(themeName, themeDir)
|
||||
@@ -156,7 +173,7 @@ class GuiPreferencesGeneral(QWidget):
|
||||
|
||||
## Select Icon Theme
|
||||
self.guiIcons = QComboBox()
|
||||
self.guiIcons.setMinimumWidth(self.mainConf.pxInt(200))
|
||||
self.guiIcons.setMinimumWidth(minWidth)
|
||||
self.theIcons = self.theTheme.theIcons.listThemes()
|
||||
for iconDir, iconName in self.theIcons:
|
||||
self.guiIcons.addItem(iconName, iconDir)
|
||||
@@ -240,6 +257,7 @@ class GuiPreferencesGeneral(QWidget):
|
||||
def saveValues(self):
|
||||
"""Save the values set for this tab.
|
||||
"""
|
||||
guiLang = self.guiLang.currentData()
|
||||
guiTheme = self.guiTheme.currentData()
|
||||
guiIcons = self.guiIcons.currentData()
|
||||
guiDark = self.guiDark.isChecked()
|
||||
@@ -248,12 +266,14 @@ class GuiPreferencesGeneral(QWidget):
|
||||
|
||||
# Check if restart is needed
|
||||
needsRestart = False
|
||||
needsRestart |= self.mainConf.guiLang != guiLang
|
||||
needsRestart |= self.mainConf.guiTheme != guiTheme
|
||||
needsRestart |= self.mainConf.guiIcons != guiIcons
|
||||
needsRestart |= self.mainConf.guiDark != guiDark
|
||||
needsRestart |= self.mainConf.guiFont != guiFont
|
||||
needsRestart |= self.mainConf.guiFontSize != guiFontSize
|
||||
|
||||
self.mainConf.guiLang = guiLang
|
||||
self.mainConf.guiTheme = guiTheme
|
||||
self.mainConf.guiIcons = guiIcons
|
||||
self.mainConf.guiDark = guiDark
|
||||
|
||||
@@ -61,6 +61,14 @@ def refDir():
|
||||
theDir = os.path.join(testDir, "reference")
|
||||
return theDir
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def filesDir():
|
||||
"""The folder where additional test files are stored.
|
||||
"""
|
||||
testDir = os.path.dirname(__file__)
|
||||
theDir = os.path.join(testDir, "files")
|
||||
return theDir
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def outDir(tmpDir):
|
||||
"""An output folder for test results
|
||||
|
||||
@@ -91,6 +91,16 @@ class DummyStatusBar():
|
||||
|
||||
# END Class DummyStatusBar
|
||||
|
||||
class DummyApp:
|
||||
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
def installTranslator(self, theLang):
|
||||
return
|
||||
|
||||
# END Class DummyApp
|
||||
|
||||
# =========================================================================== #
|
||||
# Error Functions
|
||||
# Dummy functions that will raise errors instead.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<クdハ�箆!ソ`。スン
|
||||
@@ -27,8 +27,8 @@ import configparser
|
||||
|
||||
from shutil import copyfile
|
||||
|
||||
from dummy import causeOSError
|
||||
from tools import cmpFiles
|
||||
from dummy import causeOSError, DummyApp
|
||||
from tools import cmpFiles, writeFile
|
||||
|
||||
from nw.config import Config
|
||||
from nw.constants import nwConst, nwFiles
|
||||
@@ -85,7 +85,7 @@ def testBaseConfig_Constructor(monkeypatch):
|
||||
# END Test testBaseConfig_Constructor
|
||||
|
||||
@pytest.mark.base
|
||||
def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir):
|
||||
def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir, filesDir):
|
||||
"""Test config intialisation.
|
||||
"""
|
||||
tstConf = Config()
|
||||
@@ -192,6 +192,21 @@ def testBaseConfig_Init(monkeypatch, tmpDir, fncDir, outDir, refDir):
|
||||
tstConf.doReplaceSQuote = orDoSng
|
||||
assert tstConf.saveConfig()
|
||||
|
||||
# Localisation
|
||||
i18nDir = os.path.join(fncDir, "i18n")
|
||||
os.mkdir(i18nDir)
|
||||
os.mkdir(os.path.join(i18nDir, "stuff"))
|
||||
tstConf.nwLangPath = i18nDir
|
||||
|
||||
copyfile(os.path.join(filesDir, "nw_en_GB.qm"), os.path.join(fncDir, "nw_en_GB.qm"))
|
||||
writeFile(os.path.join(i18nDir, "nw_en_GB.ts"), "")
|
||||
writeFile(os.path.join(i18nDir, "nw_abcd.qm"), "")
|
||||
|
||||
tstApp = DummyApp()
|
||||
tstConf.initLocalisation(tstApp)
|
||||
theList = tstConf.listLanguages()
|
||||
assert theList == [("en_GB", "British English")]
|
||||
|
||||
copyfile(confFile, testFile)
|
||||
assert cmpFiles(testFile, compFile, [2, 9, 10])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user