Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project basic internationalization support #673

Merged
merged 22 commits into from
Feb 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
98e3343
novelWriter i18n and portuguese translation
bkmeneguello Feb 9, 2021
c0acc1d
Move the i18n initialisation to the Config class
vkbo Feb 14, 2021
af6d968
Add docstrings and help info for the i18n tools in setup.py
vkbo Feb 14, 2021
5e30e1a
Just use Qt's own facility for loading localisation files
vkbo Feb 15, 2021
d506cf2
Fix typo and left back "print"
bkmeneguello Feb 15, 2021
dba8865
Revert some changes to how languages are loaded and remove iso.py
vkbo Feb 15, 2021
df19ced
Rewrap self.tr and fix a few bugs
vkbo Feb 15, 2021
8087e8a
Fix tests and a bug in GuiMain
vkbo Feb 15, 2021
89cf28f
Make tests work on github actions default language code
vkbo Feb 15, 2021
6d56bc7
Fix flake8 complaints
vkbo Feb 15, 2021
31b665d
Last pass of fixes and tweaks
vkbo Feb 15, 2021
2f57a4f
Resolve comment about numbered format string in dialog
vkbo Feb 15, 2021
d4b4451
Improved list and quote handling, also fix a typo
bkmeneguello Feb 15, 2021
cf79fef
Update portuguese translation
bkmeneguello Feb 15, 2021
ed356ba
Merge branch 'i18n' of https://github.com/bkmeneguello/novelWriter in…
bkmeneguello Feb 15, 2021
2e4148a
Restore some of the old spell check information in the status bar
vkbo Feb 15, 2021
8db140f
Make the number to word function ready for multiple langauges, and ma…
vkbo Feb 15, 2021
7b7bf5d
Fix a bug in parsing orphaned file names
vkbo Feb 15, 2021
8093528
Update portuguese translation
bkmeneguello Feb 16, 2021
d5bd816
Last round of changes to localisation
vkbo Feb 16, 2021
8f1c4af
Fix a bug in Build and Constants, and clean up some more nested trans…
vkbo Feb 16, 2021
65e3111
Final translations
bkmeneguello Feb 16, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added i18n/nw_pt.qm
Binary file not shown.
4,709 changes: 4,709 additions & 0 deletions i18n/nw_pt.ts

Large diffs are not rendered by default.

447 changes: 447 additions & 0 deletions i18n/phrases_pt.qph

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions novelWriter.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
SOURCES += \
nw/constants/constants.py \
nw/core/document.py \
nw/core/project.py \
nw/core/tokenizer.py \
nw/gui/about.py \
nw/gui/build.py \
nw/gui/custom.py \
nw/gui/doceditor.py \
nw/gui/docmerge.py \
nw/gui/docsplit.py \
nw/gui/docviewer.py \
nw/gui/itemdetails.py \
nw/gui/itemeditor.py \
nw/gui/mainmenu.py \
nw/gui/noveltree.py \
nw/gui/outline.py \
nw/gui/outlinedetails.py \
nw/gui/preferences.py \
nw/gui/projdetails.py \
nw/gui/projload.py \
nw/gui/projsettings.py \
nw/gui/projtree.py \
nw/gui/projwizard.py \
nw/gui/statusbar.py \
nw/gui/theme.py \
nw/gui/wordlist.py \
nw/gui/writingstats.py \
nw/error.py \
nw/guimain.py

TRANSLATIONS += \
i18n/nw_pt.ts
1 change: 1 addition & 0 deletions nw/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ def main(sysArgs=None):
sys.excepthook = exceptionHandler

# Launch main GUI
CONFIG.initLocalisation(nwApp)
nwGUI = GuiMain()
if not nwGUI.hasProject:
nwGUI.showProjectLoadDialog()
Expand Down
47 changes: 44 additions & 3 deletions nw/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@
from time import time

from PyQt5.Qt import PYQT_VERSION_STR
from PyQt5.QtCore import QT_VERSION_STR, QStandardPaths, QSysInfo
from PyQt5.QtCore import (
QT_VERSION_STR, QStandardPaths, QSysInfo, QLocale, QLibraryInfo,
QTranslator
)

from nw.constants import nwConst, nwFiles, nwUnicode
from nw.common import splitVersionNumber, formatTimeStamp
Expand Down Expand Up @@ -84,12 +87,18 @@ def __init__(self):
self.guiSyntax = "default_light"
self.guiIcons = "typicons_colour_light"
self.guiDark = False # Load icons for dark backgrounds, if available
self.guiLang = "en" # Hardcoded for now since the GUI is only in English
self.guiFont = "" # Defaults to system default font
self.guiFontSize = 11
self.guiFontSize = 11 # Is overridden if system default is loaded
self.guiScale = 1.0 # Set automatically by Theme class
self.lastNotes = "0x0" # The latest release notes that have been shown

## Localisation
self.qLocal = QLocale.system()
self.guiLang = self.qLocal.name()
self.qtLangPath = QLibraryInfo.location(QLibraryInfo.TranslationsPath)
self.nwLangPath = None
self.qtTrans = {}

## Sizes
self.winGeometry = [1200, 650]
self.treeColWidth = [200, 50, 30]
Expand Down Expand Up @@ -290,6 +299,9 @@ def initConfig(self, confPath=None, dataPath=None):
self.iconPath = os.path.join(self.assetPath, "icons")
self.appIcon = os.path.join(self.iconPath, "novelwriter.svg")

# Internationalisation
self.nwLangPath = os.path.join(self.appRoot, "i18n")

logger.verbose("App path: %s" % self.appPath)
logger.verbose("Last path: %s" % self.lastPath)

Expand Down Expand Up @@ -354,6 +366,31 @@ def initConfig(self, confPath=None, dataPath=None):

return True

def initLocalisation(self, nwApp):
"""Initialise the localisation of the GUI.
"""
self.qLocal = QLocale(self.guiLang)
QLocale.setDefault(self.qLocal)
self.qtTrans = {}

langList = [
(self.qtLangPath, "qt"), # Qt 4.x
(self.qtLangPath, "qtbase"), # Qt 5.x
(self.nwLangPath, "qtbase"), # Alternative Qt 5.x
(self.nwLangPath, "nw"), # novelWriter
]
for lngPath, lngBase in langList:
for lngCode in self.qLocal.uiLanguages():
qTrans = QTranslator()
lngFile = "%s_%s" % (lngBase, lngCode)
if lngFile not in self.qtTrans:
if qTrans.load(lngFile, lngPath):
logger.debug("Loaded: %s" % qTrans.filePath())
nwApp.installTranslator(qTrans)
self.qtTrans[lngFile] = qTrans

return

def loadConfig(self):
"""Load preferences from file and replace default settings.
"""
Expand Down Expand Up @@ -397,6 +434,9 @@ def loadConfig(self):
self.lastNotes = self._parseLine(
cnfParse, cnfSec, "lastnotes", self.CNF_STR, self.lastNotes
)
self.guiLang = self._parseLine(
cnfParse, cnfSec, "guilang", self.CNF_STR, self.guiLang
)

## Sizes
cnfSec = "Sizes"
Expand Down Expand Up @@ -626,6 +666,7 @@ def saveConfig(self):
cnfParse.set(cnfSec, "guifont", str(self.guiFont))
cnfParse.set(cnfSec, "guifontsize", str(self.guiFontSize))
cnfParse.set(cnfSec, "lastnotes", str(self.lastNotes))
cnfParse.set(cnfSec, "guilang", str(self.guiLang))

## Sizes
cnfSec = "Sizes"
Expand Down
8 changes: 3 additions & 5 deletions nw/constants/__init__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
# -*- coding: utf-8 -*-
from nw.constants.iso import isoLanguage, isoCountry
from nw.constants.constants import (
nwConst, nwLists, nwRegEx, nwFiles, nwKeyWords, nwLabels, nwQuotes,
nwUnicode, nwHtmlUnicode
trConst, nwConst, nwLists, nwRegEx, nwFiles, nwKeyWords, nwLabels,
nwQuotes, nwUnicode, nwHtmlUnicode
)
from nw.constants.enum import (
nwAlert, nwDocAction, nwItemClass, nwItemLayout, nwItemType, nwOutline,
nwDocInsert
)

__all__ = [
"isoCountry",
"isoLanguage",
"trConst",
"nwConst",
"nwLists",
"nwRegEx",
Expand Down
131 changes: 69 additions & 62 deletions nw/constants/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,17 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""

from PyQt5.QtCore import QCoreApplication, QT_TRANSLATE_NOOP

from nw.constants.enum import (
nwItemClass, nwItemLayout, nwItemType, nwOutline
)

def trConst(tString):
"""Wrapper function for locally translating constants.
"""
return QCoreApplication.translate("Constant", tString)

class nwConst():

# Date and Time Formats
Expand Down Expand Up @@ -119,17 +126,17 @@ class nwKeyWords:
class nwLabels():

CLASS_NAME = {
nwItemClass.NO_CLASS : "None",
nwItemClass.NOVEL : "Novel",
nwItemClass.PLOT : "Plot",
nwItemClass.CHARACTER : "Characters",
nwItemClass.WORLD : "Locations",
nwItemClass.TIMELINE : "Timeline",
nwItemClass.OBJECT : "Objects",
nwItemClass.ENTITY : "Entity",
nwItemClass.CUSTOM : "Custom",
nwItemClass.ARCHIVE : "Outtakes",
nwItemClass.TRASH : "Trash",
nwItemClass.NO_CLASS : QT_TRANSLATE_NOOP("Constant", "None"),
nwItemClass.NOVEL : QT_TRANSLATE_NOOP("Constant", "Novel"),
nwItemClass.PLOT : QT_TRANSLATE_NOOP("Constant", "Plot"),
nwItemClass.CHARACTER : QT_TRANSLATE_NOOP("Constant", "Characters"),
nwItemClass.WORLD : QT_TRANSLATE_NOOP("Constant", "Locations"),
nwItemClass.TIMELINE : QT_TRANSLATE_NOOP("Constant", "Timeline"),
nwItemClass.OBJECT : QT_TRANSLATE_NOOP("Constant", "Objects"),
nwItemClass.ENTITY : QT_TRANSLATE_NOOP("Constant", "Entity"),
nwItemClass.CUSTOM : QT_TRANSLATE_NOOP("Constant", "Custom"),
nwItemClass.ARCHIVE : QT_TRANSLATE_NOOP("Constant", "Outtakes"),
nwItemClass.TRASH : QT_TRANSLATE_NOOP("Constant", "Trash"),
}
CLASS_FLAG = {
nwItemClass.NO_CLASS : "0",
Expand Down Expand Up @@ -158,15 +165,15 @@ class nwLabels():
nwItemClass.TRASH : "cls_trash",
}
LAYOUT_NAME = {
nwItemLayout.NO_LAYOUT : "None",
nwItemLayout.TITLE : "Title Page",
nwItemLayout.BOOK : "Book",
nwItemLayout.PAGE : "Plain Page",
nwItemLayout.PARTITION : "Partition",
nwItemLayout.UNNUMBERED : "Unnumbered",
nwItemLayout.CHAPTER : "Chapter",
nwItemLayout.SCENE : "Scene",
nwItemLayout.NOTE : "Note",
nwItemLayout.NO_LAYOUT : QT_TRANSLATE_NOOP("Constant", "None"),
nwItemLayout.TITLE : QT_TRANSLATE_NOOP("Constant", "Title Page"),
nwItemLayout.BOOK : QT_TRANSLATE_NOOP("Constant", "Book"),
nwItemLayout.PAGE : QT_TRANSLATE_NOOP("Constant", "Plain Page"),
nwItemLayout.PARTITION : QT_TRANSLATE_NOOP("Constant", "Partition"),
nwItemLayout.UNNUMBERED : QT_TRANSLATE_NOOP("Constant", "Unnumbered"),
nwItemLayout.CHAPTER : QT_TRANSLATE_NOOP("Constant", "Chapter"),
nwItemLayout.SCENE : QT_TRANSLATE_NOOP("Constant", "Scene"),
nwItemLayout.NOTE : QT_TRANSLATE_NOOP("Constant", "Note"),
}
LAYOUT_FLAG = {
nwItemLayout.NO_LAYOUT : "Xo",
Expand All @@ -180,35 +187,35 @@ class nwLabels():
nwItemLayout.NOTE : "Nt",
}
KEY_NAME = {
nwKeyWords.TAG_KEY : "Tag",
nwKeyWords.POV_KEY : "Point of View",
nwKeyWords.FOCUS_KEY : "Focus",
nwKeyWords.CHAR_KEY : "Characters",
nwKeyWords.PLOT_KEY : "Plot",
nwKeyWords.TIME_KEY : "Timeline",
nwKeyWords.WORLD_KEY : "Locations",
nwKeyWords.OBJECT_KEY : "Objects",
nwKeyWords.ENTITY_KEY : "Entities",
nwKeyWords.CUSTOM_KEY : "Custom",
nwKeyWords.TAG_KEY : QT_TRANSLATE_NOOP("Constant", "Tag"),
nwKeyWords.POV_KEY : QT_TRANSLATE_NOOP("Constant", "Point of View"),
nwKeyWords.FOCUS_KEY : QT_TRANSLATE_NOOP("Constant", "Focus"),
nwKeyWords.CHAR_KEY : QT_TRANSLATE_NOOP("Constant", "Characters"),
nwKeyWords.PLOT_KEY : QT_TRANSLATE_NOOP("Constant", "Plot"),
nwKeyWords.TIME_KEY : QT_TRANSLATE_NOOP("Constant", "Timeline"),
nwKeyWords.WORLD_KEY : QT_TRANSLATE_NOOP("Constant", "Locations"),
nwKeyWords.OBJECT_KEY : QT_TRANSLATE_NOOP("Constant", "Objects"),
nwKeyWords.ENTITY_KEY : QT_TRANSLATE_NOOP("Constant", "Entities"),
nwKeyWords.CUSTOM_KEY : QT_TRANSLATE_NOOP("Constant", "Custom"),
}
OUTLINE_COLS = {
nwOutline.TITLE : "Title",
nwOutline.LEVEL : "Level",
nwOutline.LABEL : "Document",
nwOutline.LINE : "Line",
nwOutline.CCOUNT : "Chars",
nwOutline.WCOUNT : "Words",
nwOutline.PCOUNT : "Pars",
nwOutline.POV : "POV",
nwOutline.FOCUS : "Focus",
nwOutline.TITLE : QT_TRANSLATE_NOOP("Constant", "Title"),
nwOutline.LEVEL : QT_TRANSLATE_NOOP("Constant", "Level"),
nwOutline.LABEL : QT_TRANSLATE_NOOP("Constant", "Document"),
nwOutline.LINE : QT_TRANSLATE_NOOP("Constant", "Line"),
nwOutline.CCOUNT : QT_TRANSLATE_NOOP("Constant", "Chars"),
nwOutline.WCOUNT : QT_TRANSLATE_NOOP("Constant", "Words"),
nwOutline.PCOUNT : QT_TRANSLATE_NOOP("Constant", "Pars"),
nwOutline.POV : QT_TRANSLATE_NOOP("Constant", "POV"),
nwOutline.FOCUS : QT_TRANSLATE_NOOP("Constant", "Focus"),
nwOutline.CHAR : KEY_NAME[nwKeyWords.CHAR_KEY],
nwOutline.PLOT : KEY_NAME[nwKeyWords.PLOT_KEY],
nwOutline.TIME : KEY_NAME[nwKeyWords.TIME_KEY],
nwOutline.WORLD : KEY_NAME[nwKeyWords.WORLD_KEY],
nwOutline.OBJECT : KEY_NAME[nwKeyWords.OBJECT_KEY],
nwOutline.ENTITY : KEY_NAME[nwKeyWords.ENTITY_KEY],
nwOutline.CUSTOM : KEY_NAME[nwKeyWords.CUSTOM_KEY],
nwOutline.SYNOP : "Synopsis",
nwOutline.SYNOP : QT_TRANSLATE_NOOP("Constant", "Synopsis"),
}

# END Class nwLabels
Expand All @@ -218,28 +225,28 @@ class nwQuotes():
Source: https://en.wikipedia.org/wiki/Quotation_mark
"""
SYMBOLS = {
"\u0027" : "Straight single quotation mark",
"\u0022" : "Straight double quotation mark",

"\u2018" : "Left single quotation mark",
"\u2019" : "Right single quotation mark",
"\u201a" : "Single low-9 quotation mark",
"\u201b" : "Single high-reversed-9 quotation mark",
"\u201c" : "Left double quotation mark",
"\u201d" : "Right double quotation mark",
"\u201e" : "Double low-9 quotation mark",
"\u201f" : "Double high-reversed-9 quotation mark",
"\u2e42" : "Double low-reversed-9 quotation mark",

"\u2039" : "Single left-pointing angle quotation mark",
"\u203a" : "Single right-pointing angle quotation mark",
"\u00ab" : "Left-pointing double angle quotation mark",
"\u00bb" : "Right-pointing double angle quotation mark",

"\u300c" : "Left corner bracket",
"\u300d" : "Right corner bracket",
"\u300e" : "Left white corner bracket",
"\u300f" : "Right white corner bracket",
"\u0027" : QT_TRANSLATE_NOOP("Constant", "Straight single quotation mark"),
"\u0022" : QT_TRANSLATE_NOOP("Constant", "Straight double quotation mark"),

"\u2018" : QT_TRANSLATE_NOOP("Constant", "Left single quotation mark"),
"\u2019" : QT_TRANSLATE_NOOP("Constant", "Right single quotation mark"),
"\u201a" : QT_TRANSLATE_NOOP("Constant", "Single low-9 quotation mark"),
"\u201b" : QT_TRANSLATE_NOOP("Constant", "Single high-reversed-9 quotation mark"),
"\u201c" : QT_TRANSLATE_NOOP("Constant", "Left double quotation mark"),
"\u201d" : QT_TRANSLATE_NOOP("Constant", "Right double quotation mark"),
"\u201e" : QT_TRANSLATE_NOOP("Constant", "Double low-9 quotation mark"),
"\u201f" : QT_TRANSLATE_NOOP("Constant", "Double high-reversed-9 quotation mark"),
"\u2e42" : QT_TRANSLATE_NOOP("Constant", "Double low-reversed-9 quotation mark"),

"\u2039" : QT_TRANSLATE_NOOP("Constant", "Single left-pointing angle quotation mark"),
"\u203a" : QT_TRANSLATE_NOOP("Constant", "Single right-pointing angle quotation mark"),
"\u00ab" : QT_TRANSLATE_NOOP("Constant", "Left-pointing double angle quotation mark"),
"\u00bb" : QT_TRANSLATE_NOOP("Constant", "Right-pointing double angle quotation mark"),

"\u300c" : QT_TRANSLATE_NOOP("Constant", "Left corner bracket"),
"\u300d" : QT_TRANSLATE_NOOP("Constant", "Right corner bracket"),
"\u300e" : QT_TRANSLATE_NOOP("Constant", "Left white corner bracket"),
"\u300f" : QT_TRANSLATE_NOOP("Constant", "Right white corner bracket"),
}

# END Class nwQuotes
Expand Down
Loading