Merge pull request #676 from vkbo/tokenizer_localisation
Tokenizer Localisation
This commit is contained in:
+183
-203
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"Synopsis": "Synopsis",
|
||||||
|
"Comment": "Comment",
|
||||||
|
"Notes": "Notes",
|
||||||
|
"0": "Zero",
|
||||||
|
"1": "One",
|
||||||
|
"2": "Two",
|
||||||
|
"3": "Three",
|
||||||
|
"4": "Four",
|
||||||
|
"5": "Five",
|
||||||
|
"6": "Six",
|
||||||
|
"7": "Seven",
|
||||||
|
"8": "Eight",
|
||||||
|
"9": "Nine",
|
||||||
|
"10": "Ten",
|
||||||
|
"11": "Eleven",
|
||||||
|
"12": "Twelve",
|
||||||
|
"13": "Thirteen",
|
||||||
|
"14": "Fourteen",
|
||||||
|
"15": "Fifteen",
|
||||||
|
"16": "Sixteen",
|
||||||
|
"17": "Seventeen",
|
||||||
|
"18": "Eighteen",
|
||||||
|
"19": "Nineteen",
|
||||||
|
"20": "Twenty",
|
||||||
|
"21": "Twenty-One",
|
||||||
|
"22": "Twenty-Two",
|
||||||
|
"23": "Twenty-Three",
|
||||||
|
"24": "Twenty-Four",
|
||||||
|
"25": "Twenty-Five",
|
||||||
|
"26": "Twenty-Six",
|
||||||
|
"27": "Twenty-Seven",
|
||||||
|
"28": "Twenty-Eight",
|
||||||
|
"29": "Twenty-Nine",
|
||||||
|
"30": "Thirty",
|
||||||
|
"31": "Thirty-One",
|
||||||
|
"32": "Thirty-Two",
|
||||||
|
"33": "Thirty-Three",
|
||||||
|
"34": "Thirty-Four",
|
||||||
|
"35": "Thirty-Five",
|
||||||
|
"36": "Thirty-Six",
|
||||||
|
"37": "Thirty-Seven",
|
||||||
|
"38": "Thirty-Eight",
|
||||||
|
"39": "Thirty-Nine",
|
||||||
|
"40": "Forty",
|
||||||
|
"41": "Forty-One",
|
||||||
|
"42": "Forty-Two",
|
||||||
|
"43": "Forty-Three",
|
||||||
|
"44": "Forty-Four",
|
||||||
|
"45": "Forty-Five",
|
||||||
|
"46": "Forty-Six",
|
||||||
|
"47": "Forty-Seven",
|
||||||
|
"48": "Forty-Eight",
|
||||||
|
"49": "Forty-Nine",
|
||||||
|
"50": "Fifty",
|
||||||
|
"51": "Fifty-One",
|
||||||
|
"52": "Fifty-Two",
|
||||||
|
"53": "Fifty-Three",
|
||||||
|
"54": "Fifty-Four",
|
||||||
|
"55": "Fifty-Five",
|
||||||
|
"56": "Fifty-Six",
|
||||||
|
"57": "Fifty-Seven",
|
||||||
|
"58": "Fifty-Eight",
|
||||||
|
"59": "Fifty-Nine",
|
||||||
|
"60": "Sixty",
|
||||||
|
"61": "Sixty-One",
|
||||||
|
"62": "Sixty-Two",
|
||||||
|
"63": "Sixty-Three",
|
||||||
|
"64": "Sixty-Four",
|
||||||
|
"65": "Sixty-Five",
|
||||||
|
"66": "Sixty-Six",
|
||||||
|
"67": "Sixty-Seven",
|
||||||
|
"68": "Sixty-Eight",
|
||||||
|
"69": "Sixty-Nine",
|
||||||
|
"70": "Seventy",
|
||||||
|
"71": "Seventy-One",
|
||||||
|
"72": "Seventy-Two",
|
||||||
|
"73": "Seventy-Three",
|
||||||
|
"74": "Seventy-Four",
|
||||||
|
"75": "Seventy-Five",
|
||||||
|
"76": "Seventy-Six",
|
||||||
|
"77": "Seventy-Seven",
|
||||||
|
"78": "Seventy-Eight",
|
||||||
|
"79": "Seventy-Nine",
|
||||||
|
"80": "Eighty",
|
||||||
|
"81": "Eighty-One",
|
||||||
|
"82": "Eighty-Two",
|
||||||
|
"83": "Eighty-Three",
|
||||||
|
"84": "Eighty-Four",
|
||||||
|
"85": "Eighty-Five",
|
||||||
|
"86": "Eighty-Six",
|
||||||
|
"87": "Eighty-Seven",
|
||||||
|
"88": "Eighty-Eight",
|
||||||
|
"89": "Eighty-Nine",
|
||||||
|
"90": "Ninety",
|
||||||
|
"91": "Ninety-One",
|
||||||
|
"92": "Ninety-Two",
|
||||||
|
"93": "Ninety-Three",
|
||||||
|
"94": "Ninety-Four",
|
||||||
|
"95": "Ninety-Five",
|
||||||
|
"96": "Ninety-Six",
|
||||||
|
"97": "Ninety-Seven",
|
||||||
|
"98": "Ninety-Eight",
|
||||||
|
"99": "Ninety-Nine"
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"Synopsis": "Sammendrag",
|
||||||
|
"Comment": "Kommentar",
|
||||||
|
"Notes": "Notat",
|
||||||
|
"0": "null",
|
||||||
|
"1": "én",
|
||||||
|
"2": "to",
|
||||||
|
"3": "tre",
|
||||||
|
"4": "fire",
|
||||||
|
"5": "fem",
|
||||||
|
"6": "seks",
|
||||||
|
"7": "sju",
|
||||||
|
"8": "åtte",
|
||||||
|
"9": "ni",
|
||||||
|
"10": "ti",
|
||||||
|
"11": "elleve",
|
||||||
|
"12": "tolv",
|
||||||
|
"13": "tretten",
|
||||||
|
"14": "fjorten",
|
||||||
|
"15": "femten",
|
||||||
|
"16": "seksten",
|
||||||
|
"17": "sytten",
|
||||||
|
"18": "atten",
|
||||||
|
"19": "nitten",
|
||||||
|
"20": "tjue",
|
||||||
|
"21": "tjueén",
|
||||||
|
"22": "tjueto",
|
||||||
|
"23": "tjuetre",
|
||||||
|
"24": "tjuefire",
|
||||||
|
"25": "tjuefem",
|
||||||
|
"26": "tjueseks",
|
||||||
|
"27": "tjuesju",
|
||||||
|
"28": "tjueåtte",
|
||||||
|
"29": "tjueni",
|
||||||
|
"30": "tretti",
|
||||||
|
"31": "trettién",
|
||||||
|
"32": "trettito",
|
||||||
|
"33": "trettitre",
|
||||||
|
"34": "trettifire",
|
||||||
|
"35": "trettifem",
|
||||||
|
"36": "trettiseks",
|
||||||
|
"37": "trettisju",
|
||||||
|
"38": "trettiåtte",
|
||||||
|
"39": "trettini",
|
||||||
|
"40": "førti",
|
||||||
|
"41": "førtién",
|
||||||
|
"42": "førtito",
|
||||||
|
"43": "førtitre",
|
||||||
|
"44": "førtifire",
|
||||||
|
"45": "førtifem",
|
||||||
|
"46": "førtiseks",
|
||||||
|
"47": "førtisju",
|
||||||
|
"48": "førtiåtte",
|
||||||
|
"49": "førtini",
|
||||||
|
"50": "femti",
|
||||||
|
"51": "femtién",
|
||||||
|
"52": "femtito",
|
||||||
|
"53": "femtitre",
|
||||||
|
"54": "femtifire",
|
||||||
|
"55": "femtifem",
|
||||||
|
"56": "femtiseks",
|
||||||
|
"57": "femtisju",
|
||||||
|
"58": "femtiåtte",
|
||||||
|
"59": "femtini",
|
||||||
|
"60": "seksti",
|
||||||
|
"61": "sekstién",
|
||||||
|
"62": "sekstito",
|
||||||
|
"63": "sekstitre",
|
||||||
|
"64": "sekstifire",
|
||||||
|
"65": "sekstifem",
|
||||||
|
"66": "sekstiseks",
|
||||||
|
"67": "sekstisju",
|
||||||
|
"68": "sekstiåtte",
|
||||||
|
"69": "sekstini",
|
||||||
|
"70": "sytti",
|
||||||
|
"71": "syttién",
|
||||||
|
"72": "syttito",
|
||||||
|
"73": "syttitre",
|
||||||
|
"74": "syttifire",
|
||||||
|
"75": "syttifem",
|
||||||
|
"76": "syttiseks",
|
||||||
|
"77": "syttisju",
|
||||||
|
"78": "syttiåtte",
|
||||||
|
"79": "syttini",
|
||||||
|
"80": "åtti",
|
||||||
|
"81": "åttién",
|
||||||
|
"82": "åttito",
|
||||||
|
"83": "åttitre",
|
||||||
|
"84": "åttifire",
|
||||||
|
"85": "åttifem",
|
||||||
|
"86": "åttiseks",
|
||||||
|
"87": "åttisju",
|
||||||
|
"88": "åttiåtte",
|
||||||
|
"89": "åttini",
|
||||||
|
"90": "nitti",
|
||||||
|
"91": "nittién",
|
||||||
|
"92": "nittito",
|
||||||
|
"93": "nittitre",
|
||||||
|
"94": "nittifire",
|
||||||
|
"95": "nittifem",
|
||||||
|
"96": "nittiseks",
|
||||||
|
"97": "nittisju",
|
||||||
|
"98": "nittiåtte",
|
||||||
|
"99": "nittini"
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"Synopsis": "Samandrag",
|
||||||
|
"Comment": "Kommentar",
|
||||||
|
"Notes": "Notat",
|
||||||
|
"0": "null",
|
||||||
|
"1": "ein",
|
||||||
|
"2": "to",
|
||||||
|
"3": "tre",
|
||||||
|
"4": "fire",
|
||||||
|
"5": "fem",
|
||||||
|
"6": "seks",
|
||||||
|
"7": "sju",
|
||||||
|
"8": "åtte",
|
||||||
|
"9": "ni",
|
||||||
|
"10": "ti",
|
||||||
|
"11": "elleve",
|
||||||
|
"12": "tolv",
|
||||||
|
"13": "tretten",
|
||||||
|
"14": "fjorten",
|
||||||
|
"15": "femten",
|
||||||
|
"16": "seksten",
|
||||||
|
"17": "sytten",
|
||||||
|
"18": "atten",
|
||||||
|
"19": "nitten",
|
||||||
|
"20": "tjue",
|
||||||
|
"21": "tjueein",
|
||||||
|
"22": "tjueto",
|
||||||
|
"23": "tjuetre",
|
||||||
|
"24": "tjuefire",
|
||||||
|
"25": "tjuefem",
|
||||||
|
"26": "tjueseks",
|
||||||
|
"27": "tjuesju",
|
||||||
|
"28": "tjueåtte",
|
||||||
|
"29": "tjueni",
|
||||||
|
"30": "tretti",
|
||||||
|
"31": "trettiein",
|
||||||
|
"32": "trettito",
|
||||||
|
"33": "trettitre",
|
||||||
|
"34": "trettifire",
|
||||||
|
"35": "trettifem",
|
||||||
|
"36": "trettiseks",
|
||||||
|
"37": "trettisju",
|
||||||
|
"38": "trettiåtte",
|
||||||
|
"39": "trettini",
|
||||||
|
"40": "førti",
|
||||||
|
"41": "førtiein",
|
||||||
|
"42": "førtito",
|
||||||
|
"43": "førtitre",
|
||||||
|
"44": "førtifire",
|
||||||
|
"45": "førtifem",
|
||||||
|
"46": "førtiseks",
|
||||||
|
"47": "førtisju",
|
||||||
|
"48": "førtiåtte",
|
||||||
|
"49": "førtini",
|
||||||
|
"50": "femti",
|
||||||
|
"51": "femtiein",
|
||||||
|
"52": "femtito",
|
||||||
|
"53": "femtitre",
|
||||||
|
"54": "femtifire",
|
||||||
|
"55": "femtifem",
|
||||||
|
"56": "femtiseks",
|
||||||
|
"57": "femtisju",
|
||||||
|
"58": "femtiåtte",
|
||||||
|
"59": "femtini",
|
||||||
|
"60": "seksti",
|
||||||
|
"61": "sekstiein",
|
||||||
|
"62": "sekstito",
|
||||||
|
"63": "sekstitre",
|
||||||
|
"64": "sekstifire",
|
||||||
|
"65": "sekstifem",
|
||||||
|
"66": "sekstiseks",
|
||||||
|
"67": "sekstisju",
|
||||||
|
"68": "sekstiåtte",
|
||||||
|
"69": "sekstini",
|
||||||
|
"70": "sytti",
|
||||||
|
"71": "syttiein",
|
||||||
|
"72": "syttito",
|
||||||
|
"73": "syttitre",
|
||||||
|
"74": "syttifire",
|
||||||
|
"75": "syttifem",
|
||||||
|
"76": "syttiseks",
|
||||||
|
"77": "syttisju",
|
||||||
|
"78": "syttiåtte",
|
||||||
|
"79": "syttini",
|
||||||
|
"80": "åtti",
|
||||||
|
"81": "åttiein",
|
||||||
|
"82": "åttito",
|
||||||
|
"83": "åttitre",
|
||||||
|
"84": "åttifire",
|
||||||
|
"85": "åttifem",
|
||||||
|
"86": "åttiseks",
|
||||||
|
"87": "åttisju",
|
||||||
|
"88": "åttiåtte",
|
||||||
|
"89": "åttini",
|
||||||
|
"90": "nitti",
|
||||||
|
"91": "nittiein",
|
||||||
|
"92": "nittito",
|
||||||
|
"93": "nittitre",
|
||||||
|
"94": "nittifire",
|
||||||
|
"95": "nittifem",
|
||||||
|
"96": "nittiseks",
|
||||||
|
"97": "nittisju",
|
||||||
|
"98": "nittiåtte",
|
||||||
|
"99": "nittini"
|
||||||
|
}
|
||||||
@@ -76,6 +76,7 @@ class Config:
|
|||||||
self.themeRoot = None # The full path to the nw/assets/themes folder
|
self.themeRoot = None # The full path to the nw/assets/themes folder
|
||||||
self.dictPath = None # The full path to the nw/assets/dict folder
|
self.dictPath = None # The full path to the nw/assets/dict folder
|
||||||
self.iconPath = None # The full path to the nw/assets/icons folder
|
self.iconPath = None # The full path to the nw/assets/icons folder
|
||||||
|
self.langPath = None # The full path to the nw/assets/lang folder
|
||||||
self.helpPath = None # The full path to the novelwriter .qhc help file
|
self.helpPath = None # The full path to the novelwriter .qhc help file
|
||||||
|
|
||||||
# Runtime Settings and Variables
|
# Runtime Settings and Variables
|
||||||
@@ -297,6 +298,7 @@ class Config:
|
|||||||
self.themeRoot = os.path.join(self.assetPath, "themes")
|
self.themeRoot = os.path.join(self.assetPath, "themes")
|
||||||
self.dictPath = os.path.join(self.assetPath, "dict")
|
self.dictPath = os.path.join(self.assetPath, "dict")
|
||||||
self.iconPath = os.path.join(self.assetPath, "icons")
|
self.iconPath = os.path.join(self.assetPath, "icons")
|
||||||
|
self.langPath = os.path.join(self.assetPath, "lang")
|
||||||
self.appIcon = os.path.join(self.iconPath, "novelwriter.svg")
|
self.appIcon = os.path.join(self.iconPath, "novelwriter.svg")
|
||||||
|
|
||||||
# Internationalisation
|
# Internationalisation
|
||||||
|
|||||||
+1
-2
@@ -7,12 +7,11 @@ from nw.core.spellcheck import NWSpellCheck, NWSpellEnchant, NWSpellSimple
|
|||||||
from nw.core.tohtml import ToHtml
|
from nw.core.tohtml import ToHtml
|
||||||
from nw.core.toodt import ToOdt
|
from nw.core.toodt import ToOdt
|
||||||
from nw.core.tomd import ToMarkdown
|
from nw.core.tomd import ToMarkdown
|
||||||
from nw.core.tools import countWords, numberToRoman, numberToWord
|
from nw.core.tools import countWords, numberToRoman
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"countWords",
|
"countWords",
|
||||||
"numberToRoman",
|
"numberToRoman",
|
||||||
"numberToWord",
|
|
||||||
"NWDoc",
|
"NWDoc",
|
||||||
"NWIndex",
|
"NWIndex",
|
||||||
"NWProject",
|
"NWProject",
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
import nw
|
import nw
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
@@ -61,6 +62,7 @@ class NWProject():
|
|||||||
# Core Elements
|
# Core Elements
|
||||||
self.optState = OptionState(self) # Project-specific GUI options
|
self.optState = OptionState(self) # Project-specific GUI options
|
||||||
self.projTree = NWTree(self) # The project tree
|
self.projTree = NWTree(self) # The project tree
|
||||||
|
self.langData = {} # Localisation data
|
||||||
|
|
||||||
# Project Status
|
# Project Status
|
||||||
self.projOpened = 0 # The time stamp of when the project file was opened
|
self.projOpened = 0 # The time stamp of when the project file was opened
|
||||||
@@ -622,6 +624,7 @@ class NWProject():
|
|||||||
self.theParent.setStatus(self.tr("Opened Project: {0}").format(self.projName))
|
self.theParent.setStatus(self.tr("Opened Project: {0}").format(self.projName))
|
||||||
|
|
||||||
self._scanProjectFolder()
|
self._scanProjectFolder()
|
||||||
|
self.loadProjectLocalisation(self.projLang)
|
||||||
|
|
||||||
self.currWCount = self.lastWCount
|
self.currWCount = self.lastWCount
|
||||||
self.projOpened = time()
|
self.projOpened = time()
|
||||||
@@ -1046,6 +1049,7 @@ class NWProject():
|
|||||||
theLang = checkString(theLang, None, True)
|
theLang = checkString(theLang, None, True)
|
||||||
if self.projLang != theLang:
|
if self.projLang != theLang:
|
||||||
self.projLang = theLang
|
self.projLang = theLang
|
||||||
|
self.loadProjectLocalisation(theLang)
|
||||||
self.setProjectChanged(True)
|
self.setProjectChanged(True)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -1233,6 +1237,44 @@ class NWProject():
|
|||||||
self.importItems.countEntry(nwItem.itemStatus)
|
self.importItems.countEntry(nwItem.itemStatus)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def localLookup(self, theWord):
|
||||||
|
"""Look up a word in the translation map for the project and
|
||||||
|
return it. The variable is cast to a string before lookup. If
|
||||||
|
the word does not exist, it returns itself.
|
||||||
|
"""
|
||||||
|
theValue = str(theWord)
|
||||||
|
return self.langData.get(theValue, theValue)
|
||||||
|
|
||||||
|
def loadProjectLocalisation(self, theLang):
|
||||||
|
"""Load the language data for the current project language.
|
||||||
|
"""
|
||||||
|
if theLang is None:
|
||||||
|
theLang = self.mainConf.spellLanguage
|
||||||
|
if theLang is None:
|
||||||
|
theLang = "en"
|
||||||
|
|
||||||
|
lngShort = theLang.split("_")[0]
|
||||||
|
loadFile = os.path.join(self.mainConf.langPath, "project_en.json")
|
||||||
|
chkFile1 = os.path.join(self.mainConf.langPath, "project_%s.json" % theLang)
|
||||||
|
chkFile2 = os.path.join(self.mainConf.langPath, "project_%s.json" % lngShort)
|
||||||
|
|
||||||
|
if os.path.isfile(chkFile1):
|
||||||
|
loadFile = chkFile1
|
||||||
|
elif os.path.isfile(chkFile2):
|
||||||
|
loadFile = chkFile2
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(loadFile, mode="r", encoding="utf8") as inFile:
|
||||||
|
self.langData = json.load(inFile)
|
||||||
|
logger.debug("Loaded project language file: %s" % os.path.basename(loadFile))
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
logger.error("Failed to load index file")
|
||||||
|
nw.logException()
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
##
|
##
|
||||||
# Internal Functions
|
# Internal Functions
|
||||||
##
|
##
|
||||||
|
|||||||
+6
-10
@@ -405,24 +405,20 @@ class ToHtml(Tokenizer):
|
|||||||
def _formatSynopsis(self, tText):
|
def _formatSynopsis(self, tText):
|
||||||
"""Apply HTML formatting to synopsis.
|
"""Apply HTML formatting to synopsis.
|
||||||
"""
|
"""
|
||||||
|
sSynop = self._localLookup("Synopsis")
|
||||||
if self.genMode == self.M_PREVIEW:
|
if self.genMode == self.M_PREVIEW:
|
||||||
return "<p class='comment'><span class='synopsis'>%s:</span> %s</p>\n" % (
|
return f"<p class='comment'><span class='synopsis'>{sSynop}:</span> {tText}</p>\n"
|
||||||
self._trSynopsis, tText
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return "<p class='synopsis'><strong>%s:</strong> %s</p>\n" % (
|
return f"<p class='synopsis'><strong>{sSynop}:</strong> {tText}</p>\n"
|
||||||
self._trSynopsis, tText
|
|
||||||
)
|
|
||||||
|
|
||||||
def _formatComments(self, tText):
|
def _formatComments(self, tText):
|
||||||
"""Apply HTML formatting to comments.
|
"""Apply HTML formatting to comments.
|
||||||
"""
|
"""
|
||||||
if self.genMode == self.M_PREVIEW:
|
if self.genMode == self.M_PREVIEW:
|
||||||
return "<p class='comment'>%s</p>\n" % tText
|
return f"<p class='comment'>{tText}</p>\n"
|
||||||
else:
|
else:
|
||||||
return "<p class='comment'><strong>%s:</strong> %s</p>\n" % (
|
sComm = self._localLookup("Comment")
|
||||||
self._trComment, tText
|
return f"<p class='comment'><strong>{sComm}:</strong> {tText}</p>\n"
|
||||||
)
|
|
||||||
|
|
||||||
def _formatKeywords(self, tText):
|
def _formatKeywords(self, tText):
|
||||||
"""Apply HTML formatting to keywords.
|
"""Apply HTML formatting to keywords.
|
||||||
|
|||||||
+7
-14
@@ -33,7 +33,7 @@ from functools import partial
|
|||||||
from PyQt5.QtCore import QCoreApplication, QRegularExpression
|
from PyQt5.QtCore import QCoreApplication, QRegularExpression
|
||||||
|
|
||||||
from nw.core.document import NWDoc
|
from nw.core.document import NWDoc
|
||||||
from nw.core.tools import numberToWord, numberToRoman
|
from nw.core.tools import numberToRoman
|
||||||
from nw.constants import nwConst, nwUnicode, nwItemLayout, nwItemType, nwRegEx
|
from nw.constants import nwConst, nwUnicode, nwItemLayout, nwItemType, nwRegEx
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -143,18 +143,10 @@ class Tokenizer():
|
|||||||
# Error Handling
|
# Error Handling
|
||||||
self.errData = []
|
self.errData = []
|
||||||
|
|
||||||
# Internal Mappings
|
# Function Mapping
|
||||||
|
self._localLookup = self.theProject.localLookup
|
||||||
self.tr = partial(QCoreApplication.translate, "Tokenizer")
|
self.tr = partial(QCoreApplication.translate, "Tokenizer")
|
||||||
|
|
||||||
# Localisation
|
|
||||||
self._trSynopsis = self.tr("Synopsis")
|
|
||||||
self._trComment = self.tr("Comment")
|
|
||||||
self._trNotes = self.tr("Notes")
|
|
||||||
|
|
||||||
self._spellLang = self.theProject.projLang
|
|
||||||
if self._spellLang is None:
|
|
||||||
self._spellLang = self.theParent.mainConf.spellLanguage
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
##
|
##
|
||||||
@@ -263,7 +255,7 @@ class Tokenizer():
|
|||||||
if theItem.itemType != nwItemType.ROOT:
|
if theItem.itemType != nwItemType.ROOT:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
theTitle = self.tr("{0}: {1}").format(self._trNotes, theItem.itemName)
|
theTitle = "%s: %s" % (self._localLookup("Notes"), theItem.itemName)
|
||||||
self.theTokens = []
|
self.theTokens = []
|
||||||
self.theTokens.append((
|
self.theTokens.append((
|
||||||
self.T_TITLE, 0, theTitle, None, self.A_PBB | self.A_CENTRE
|
self.T_TITLE, 0, theTitle, None, self.A_PBB | self.A_CENTRE
|
||||||
@@ -667,11 +659,12 @@ class Tokenizer():
|
|||||||
theTitle = theTitle.replace(r"%sc%", str(self.numChScene))
|
theTitle = theTitle.replace(r"%sc%", str(self.numChScene))
|
||||||
theTitle = theTitle.replace(r"%sca%", str(self.numAbsScene))
|
theTitle = theTitle.replace(r"%sca%", str(self.numAbsScene))
|
||||||
if r"%chw%" in theTitle:
|
if r"%chw%" in theTitle:
|
||||||
theTitle = theTitle.replace(r"%chw%", numberToWord(self.numChapter, self._spellLang))
|
theTitle = theTitle.replace(r"%chw%", self._localLookup(self.numChapter))
|
||||||
if r"%chi%" in theTitle:
|
if r"%chi%" in theTitle:
|
||||||
theTitle = theTitle.replace(r"%chi%", numberToRoman(self.numChapter, True))
|
theTitle = theTitle.replace(r"%chi%", numberToRoman(self.numChapter, True))
|
||||||
if r"%chI%" in theTitle:
|
if r"%chI%" in theTitle:
|
||||||
theTitle = theTitle.replace(r"%chI%", numberToRoman(self.numChapter, False))
|
theTitle = theTitle.replace(r"%chI%", numberToRoman(self.numChapter, False))
|
||||||
return theTitle
|
|
||||||
|
return theTitle[:1].upper() + theTitle[1:]
|
||||||
|
|
||||||
# END Class Tokenizer
|
# END Class Tokenizer
|
||||||
|
|||||||
+2
-2
@@ -134,10 +134,10 @@ class ToMarkdown(Tokenizer):
|
|||||||
thisPar.append(tTemp.rstrip() + " ")
|
thisPar.append(tTemp.rstrip() + " ")
|
||||||
|
|
||||||
elif tType == self.T_SYNOPSIS and self.doSynopsis:
|
elif tType == self.T_SYNOPSIS and self.doSynopsis:
|
||||||
tmpResult.append("**Synopsis:** %s\n\n" % tText)
|
tmpResult.append("**%s:** %s\n\n" % (self._localLookup("Synopsis"), tText))
|
||||||
|
|
||||||
elif tType == self.T_COMMENT and self.doComments:
|
elif tType == self.T_COMMENT and self.doComments:
|
||||||
tmpResult.append("**Comment:** %s\n\n" % tText)
|
tmpResult.append("**%s:** %s\n\n" % (self._localLookup("Comment"), tText))
|
||||||
|
|
||||||
elif tType == self.T_KEYWORD and self.doKeywords:
|
elif tType == self.T_KEYWORD and self.doKeywords:
|
||||||
tmpResult.append(self._formatKeywords(tText, tStyle))
|
tmpResult.append(self._formatKeywords(tText, tStyle))
|
||||||
|
|||||||
+7
-5
@@ -507,15 +507,17 @@ class ToOdt(Tokenizer):
|
|||||||
def _formatSynopsis(self, tText):
|
def _formatSynopsis(self, tText):
|
||||||
"""Apply formatting to synopsis lines.
|
"""Apply formatting to synopsis lines.
|
||||||
"""
|
"""
|
||||||
rTxt = "**Synopsis:** %s" % tText
|
sSynop = self._localLookup("Synopsis")
|
||||||
rFmt = "_B b_ %s" % (" "*len(tText))
|
rTxt = "**%s:** %s" % (sSynop, tText)
|
||||||
|
rFmt = "_B%s b_ %s" % (" "*len(sSynop), " "*len(tText))
|
||||||
return rTxt, rFmt
|
return rTxt, rFmt
|
||||||
|
|
||||||
def _formatComments(self, tText):
|
def _formatComments(self, tText):
|
||||||
"""Apply formatting to comments.
|
"""Apply formatting to comments.
|
||||||
"""
|
"""
|
||||||
rTxt = "**Comment:** %s" % tText
|
sComm = self._localLookup("Comment")
|
||||||
rFmt = "_B b_ %s" % (" "*len(tText))
|
rTxt = "**%s:** %s" % (sComm, tText)
|
||||||
|
rFmt = "_B%s b_ %s" % (" "*len(sComm), " "*len(tText))
|
||||||
return rTxt, rFmt
|
return rTxt, rFmt
|
||||||
|
|
||||||
def _formatKeywords(self, tText):
|
def _formatKeywords(self, tText):
|
||||||
@@ -530,7 +532,7 @@ class ToOdt(Tokenizer):
|
|||||||
if theBits[0] in nwLabels.KEY_NAME:
|
if theBits[0] in nwLabels.KEY_NAME:
|
||||||
tText = nwLabels.KEY_NAME[theBits[0]]
|
tText = nwLabels.KEY_NAME[theBits[0]]
|
||||||
rTxt += "**%s:** " % tText
|
rTxt += "**%s:** " % tText
|
||||||
rFmt += "_B%s b_ " % (" "*len(tText))
|
rFmt += "_B%s b_ " % (" "*len(tText))
|
||||||
if len(theBits) > 1:
|
if len(theBits) > 1:
|
||||||
if theBits[0] == nwKeyWords.TAG_KEY:
|
if theBits[0] == nwKeyWords.TAG_KEY:
|
||||||
rTxt += "%s" % theBits[1]
|
rTxt += "%s" % theBits[1]
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ Various core tool functions
|
|||||||
|
|
||||||
File History:
|
File History:
|
||||||
Created: 2019-04-22 [0.0.1] countWords
|
Created: 2019-04-22 [0.0.1] countWords
|
||||||
Created: 2019-10-13 [0.2.3] numberToWord, _numberToWordEN
|
|
||||||
Merged: 2020-05-08 [0.4.5] All of the above into this file
|
|
||||||
Created: 2020-07-05 [0.10.0] numberToRoman
|
Created: 2020-07-05 [0.10.0] numberToRoman
|
||||||
|
|
||||||
This file is a part of novelWriter
|
This file is a part of novelWriter
|
||||||
@@ -118,126 +116,3 @@ def numberToRoman(numVal, isLower=False):
|
|||||||
break
|
break
|
||||||
|
|
||||||
return romNum.lower() if isLower else romNum
|
return romNum.lower() if isLower else romNum
|
||||||
|
|
||||||
# =============================================================================================== #
|
|
||||||
# Convert an Integer to a Number String
|
|
||||||
# =============================================================================================== #
|
|
||||||
|
|
||||||
def numberToWord(numVal, theLang):
|
|
||||||
"""Wrapper for converting numbers to words for chapter headings.
|
|
||||||
"""
|
|
||||||
if not isinstance(numVal, int):
|
|
||||||
return "[NaN]"
|
|
||||||
|
|
||||||
if numVal < 0:
|
|
||||||
return "[<0]"
|
|
||||||
|
|
||||||
if numVal > 999:
|
|
||||||
return "[>999]"
|
|
||||||
|
|
||||||
numWord = ""
|
|
||||||
theCode = theLang.split("_")[0]
|
|
||||||
if theCode == "en":
|
|
||||||
numWord = _numberToWord_EN(numVal)
|
|
||||||
elif theCode in ("nb", "nn"):
|
|
||||||
numWord = _numberToWord_NO(numVal, theCode)
|
|
||||||
else:
|
|
||||||
# Default to return the number as a string
|
|
||||||
numWord = str(numVal)
|
|
||||||
|
|
||||||
return numWord
|
|
||||||
|
|
||||||
def _numberToWord_EN(numVal):
|
|
||||||
"""Convert numbers to English words.
|
|
||||||
"""
|
|
||||||
oneWord = ""
|
|
||||||
tenWord = ""
|
|
||||||
hunWord = ""
|
|
||||||
|
|
||||||
if numVal == 0:
|
|
||||||
return "Zero"
|
|
||||||
|
|
||||||
oneVal = numVal % 10
|
|
||||||
tenVal = (numVal - oneVal) % 100
|
|
||||||
hunVal = (numVal - tenVal - oneVal) % 1000
|
|
||||||
|
|
||||||
theWords = {
|
|
||||||
0: "", 1: "One", 2: "Two", 3: "Three", 4: "Four", 5: "Five",
|
|
||||||
6: "Six", 7: "Seven", 8: "Eight", 9: "Nine", 10: "Ten",
|
|
||||||
11: "Eleven", 12: "Twelve", 13: "Thirteen", 14: "Fourteen",
|
|
||||||
15: "Fifteen", 16: "Sixteen", 17: "Seventeen", 18: "Eighteen",
|
|
||||||
19: "Nineteen", 20: "Twenty", 30: "Thirty", 40: "Forty",
|
|
||||||
50: "Fifty", 60: "Sixty", 70: "Seventy", 80: "Eighty",
|
|
||||||
90: "Ninety", 100: "One Hundred", 200: "Two Hundred",
|
|
||||||
300: "Three Hundred", 400: "Four Hundred", 500: "Five Hundred",
|
|
||||||
600: "Six Hundred", 700: "Seven Hundred", 800: "Eight Hundred",
|
|
||||||
900: "Nine Hundred",
|
|
||||||
}
|
|
||||||
|
|
||||||
retVal = ""
|
|
||||||
hunWord = theWords.get(hunVal, "")
|
|
||||||
if tenVal == 10:
|
|
||||||
oneWord = theWords.get(oneVal+10, "")
|
|
||||||
retVal = f"{hunWord} {oneWord}".strip()
|
|
||||||
else:
|
|
||||||
oneWord = theWords.get(oneVal, "")
|
|
||||||
if tenVal == 0:
|
|
||||||
retVal = f"{hunWord} {oneWord}".strip()
|
|
||||||
else:
|
|
||||||
tenWord = theWords.get(tenVal, "")
|
|
||||||
if oneVal == 0:
|
|
||||||
retVal = f"{hunWord} {tenWord}".strip()
|
|
||||||
else:
|
|
||||||
retVal = f"{hunWord} {tenWord}-{oneWord}".strip()
|
|
||||||
|
|
||||||
return retVal
|
|
||||||
|
|
||||||
def _numberToWord_NO(numVal, theCode):
|
|
||||||
"""Convert numbers to Norwegian words.
|
|
||||||
"""
|
|
||||||
oneWord = ""
|
|
||||||
tenWord = ""
|
|
||||||
hunWord = ""
|
|
||||||
|
|
||||||
if numVal == 0:
|
|
||||||
return "null"
|
|
||||||
|
|
||||||
oneVal = numVal % 10
|
|
||||||
tenVal = (numVal - oneVal) % 100
|
|
||||||
hunVal = (numVal - tenVal - oneVal) % 1000
|
|
||||||
|
|
||||||
theWords = {
|
|
||||||
0: "", 1: "én", 2: "to", 3: "tre", 4: "fire", 5: "fem", 6: "seks",
|
|
||||||
7: "sju", 8: "åtte", 9: "ni", 10: "ti", 11: "elleve", 12: "tolv",
|
|
||||||
13: "tretten", 14: "fjorten", 15: "femten", 16: "seksten", 17: "sytten",
|
|
||||||
18: "atten", 19: "nitten", 20: "tjue", 30: "tretti", 40: "førti",
|
|
||||||
50: "femti", 60: "seksti", 70: "sytti", 80: "åtti", 90: "nitti",
|
|
||||||
100: "ett hundre", 200: "to hundre", 300: "tre hundre", 400: "fire hundre",
|
|
||||||
500: "fem hundre", 600: "seks hundre", 700: "sju hundre",
|
|
||||||
800: "åtte hundre", 900: "ni hundre",
|
|
||||||
}
|
|
||||||
|
|
||||||
if theCode == "nn":
|
|
||||||
theWords[1] = "ein"
|
|
||||||
theWords[100] = "eitt hundre"
|
|
||||||
|
|
||||||
retVal = ""
|
|
||||||
hunWord = theWords.get(hunVal, "")
|
|
||||||
if tenVal == 10:
|
|
||||||
oneWord = theWords.get(oneVal+10, "")
|
|
||||||
sepVal = " og " if hunWord and oneWord else " "
|
|
||||||
retVal = f"{hunWord}{sepVal}{oneWord}"
|
|
||||||
else:
|
|
||||||
oneWord = theWords.get(oneVal, "")
|
|
||||||
if tenVal == 0:
|
|
||||||
sepVal = " og " if hunWord and oneWord else " "
|
|
||||||
retVal = f"{hunWord}{sepVal}{oneWord}".strip()
|
|
||||||
else:
|
|
||||||
tenWord = theWords.get(tenVal, "")
|
|
||||||
sepVal = " og " if hunWord and tenWord else " "
|
|
||||||
if oneVal == 0:
|
|
||||||
retVal = f"{hunWord}{sepVal}{tenWord}".strip()
|
|
||||||
else:
|
|
||||||
retVal = f"{hunWord}{sepVal}{tenWord}{oneWord}".strip()
|
|
||||||
|
|
||||||
return retVal.strip()
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ class GuiPreferences(PagedDialog):
|
|||||||
logger.debug("Saving new preferences")
|
logger.debug("Saving new preferences")
|
||||||
|
|
||||||
needsRestart = self.tabGeneral.saveValues()
|
needsRestart = self.tabGeneral.saveValues()
|
||||||
|
prevSpell = self.mainConf.spellLanguage
|
||||||
|
|
||||||
self.tabProjects.saveValues()
|
self.tabProjects.saveValues()
|
||||||
self.tabDocs.saveValues()
|
self.tabDocs.saveValues()
|
||||||
@@ -98,6 +99,9 @@ class GuiPreferences(PagedDialog):
|
|||||||
self.tabSyntax.saveValues()
|
self.tabSyntax.saveValues()
|
||||||
self.tabAuto.saveValues()
|
self.tabAuto.saveValues()
|
||||||
|
|
||||||
|
if prevSpell != self.mainConf.spellLanguage:
|
||||||
|
self.theProject.loadProjectLocalisation(self.mainConf.spellLanguage)
|
||||||
|
|
||||||
if needsRestart:
|
if needsRestart:
|
||||||
self.theParent.makeAlert(
|
self.theParent.makeAlert(
|
||||||
self.tr("Some changes will not be applied until novelWriter has been restarted."),
|
self.tr("Some changes will not be applied until novelWriter has been restarted."),
|
||||||
|
|||||||
@@ -112,11 +112,14 @@ def testCoreToken_Setters(dummyGUI):
|
|||||||
# END Test testCoreToken_Setters
|
# END Test testCoreToken_Setters
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToken_TextOps(monkeypatch, nwMinimal, dummyGUI):
|
def testCoreToken_TextOps(monkeypatch, nwMinimal, dummyGUI, tmpConf):
|
||||||
"""Test handling files and text in the Tokenizer class.
|
"""Test handling files and text in the Tokenizer class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(dummyGUI)
|
theProject = NWProject(dummyGUI)
|
||||||
|
theProject.mainConf = tmpConf
|
||||||
theProject.projTree.setSeed(42)
|
theProject.projTree.setSeed(42)
|
||||||
|
theProject.loadProjectLocalisation("en")
|
||||||
|
|
||||||
theToken = Tokenizer(theProject, dummyGUI)
|
theToken = Tokenizer(theProject, dummyGUI)
|
||||||
theToken.setKeepMarkdown(True)
|
theToken.setKeepMarkdown(True)
|
||||||
|
|
||||||
@@ -408,10 +411,12 @@ def testCoreToken_Tokenize(dummyGUI):
|
|||||||
# END Test testCoreToken_Tokenize
|
# END Test testCoreToken_Tokenize
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToken_Headers(dummyGUI):
|
def testCoreToken_Headers(dummyGUI, tmpConf):
|
||||||
"""Test the header and page parser of the Tokenizer class.
|
"""Test the header and page parser of the Tokenizer class.
|
||||||
"""
|
"""
|
||||||
theProject = NWProject(dummyGUI)
|
theProject = NWProject(dummyGUI)
|
||||||
|
theProject.mainConf = tmpConf
|
||||||
|
theProject.loadProjectLocalisation("en")
|
||||||
theToken = Tokenizer(theProject, dummyGUI)
|
theToken = Tokenizer(theProject, dummyGUI)
|
||||||
|
|
||||||
# Nothing
|
# Nothing
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from nw.core.tools import countWords, numberToRoman, numberToWord
|
from nw.core.tools import countWords, numberToRoman
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreTools_CountWords():
|
def testCoreTools_CountWords():
|
||||||
@@ -81,80 +81,3 @@ def testCoreTools_RomanNumbers():
|
|||||||
assert numberToRoman(999, True) == "cmxcix"
|
assert numberToRoman(999, True) == "cmxcix"
|
||||||
|
|
||||||
# END Test testCoreTools_RomanNumbers
|
# END Test testCoreTools_RomanNumbers
|
||||||
|
|
||||||
@pytest.mark.core
|
|
||||||
def testCoreTools_NumberWords():
|
|
||||||
"""Test the conversion of integer to English words.
|
|
||||||
"""
|
|
||||||
# English
|
|
||||||
assert numberToWord(0, "en") == "Zero"
|
|
||||||
assert numberToWord(1, "en") == "One"
|
|
||||||
assert numberToWord(2, "en") == "Two"
|
|
||||||
assert numberToWord(3, "en") == "Three"
|
|
||||||
assert numberToWord(4, "en") == "Four"
|
|
||||||
assert numberToWord(5, "en") == "Five"
|
|
||||||
assert numberToWord(6, "en") == "Six"
|
|
||||||
assert numberToWord(7, "en") == "Seven"
|
|
||||||
assert numberToWord(8, "en") == "Eight"
|
|
||||||
assert numberToWord(9, "en") == "Nine"
|
|
||||||
assert numberToWord(10, "en") == "Ten"
|
|
||||||
assert numberToWord(11, "en") == "Eleven"
|
|
||||||
assert numberToWord(12, "en") == "Twelve"
|
|
||||||
assert numberToWord(13, "en") == "Thirteen"
|
|
||||||
assert numberToWord(14, "en") == "Fourteen"
|
|
||||||
assert numberToWord(15, "en") == "Fifteen"
|
|
||||||
assert numberToWord(16, "en") == "Sixteen"
|
|
||||||
assert numberToWord(17, "en") == "Seventeen"
|
|
||||||
assert numberToWord(18, "en") == "Eighteen"
|
|
||||||
assert numberToWord(19, "en") == "Nineteen"
|
|
||||||
assert numberToWord(20, "en") == "Twenty"
|
|
||||||
assert numberToWord(21, "en") == "Twenty-One"
|
|
||||||
assert numberToWord(29, "en") == "Twenty-Nine"
|
|
||||||
assert numberToWord(42, "en") == "Forty-Two"
|
|
||||||
assert numberToWord(114, "en") == "One Hundred Fourteen"
|
|
||||||
assert numberToWord(142, "en") == "One Hundred Forty-Two"
|
|
||||||
assert numberToWord(999, "en") == "Nine Hundred Ninety-Nine"
|
|
||||||
|
|
||||||
# Norwegian
|
|
||||||
assert numberToWord(0, "nb") == "null"
|
|
||||||
assert numberToWord(1, "nb") == "én"
|
|
||||||
assert numberToWord(10, "nb") == "ti"
|
|
||||||
assert numberToWord(20, "nb") == "tjue"
|
|
||||||
assert numberToWord(21, "nb") == "tjueén"
|
|
||||||
assert numberToWord(29, "nb") == "tjueni"
|
|
||||||
assert numberToWord(42, "nb") == "førtito"
|
|
||||||
assert numberToWord(60, "nb") == "seksti"
|
|
||||||
assert numberToWord(100, "nb") == "ett hundre"
|
|
||||||
assert numberToWord(114, "nb") == "ett hundre og fjorten"
|
|
||||||
assert numberToWord(142, "nb") == "ett hundre og førtito"
|
|
||||||
assert numberToWord(999, "nb") == "ni hundre og nittini"
|
|
||||||
|
|
||||||
assert numberToWord(0, "nn") == "null"
|
|
||||||
assert numberToWord(1, "nn") == "ein"
|
|
||||||
assert numberToWord(10, "nn") == "ti"
|
|
||||||
assert numberToWord(20, "nn") == "tjue"
|
|
||||||
assert numberToWord(21, "nn") == "tjueein"
|
|
||||||
assert numberToWord(29, "nn") == "tjueni"
|
|
||||||
assert numberToWord(42, "nn") == "førtito"
|
|
||||||
assert numberToWord(60, "nn") == "seksti"
|
|
||||||
assert numberToWord(100, "nn") == "eitt hundre"
|
|
||||||
assert numberToWord(114, "nn") == "eitt hundre og fjorten"
|
|
||||||
assert numberToWord(142, "nn") == "eitt hundre og førtito"
|
|
||||||
assert numberToWord(999, "nn") == "ni hundre og nittini"
|
|
||||||
|
|
||||||
# Check complex language setting
|
|
||||||
assert numberToWord(1, "en_GB") == "One"
|
|
||||||
assert numberToWord(2, "en_GB") == "Two"
|
|
||||||
assert numberToWord(3, "en_GB") == "Three"
|
|
||||||
|
|
||||||
# Check a few with a nonsense language setting
|
|
||||||
assert numberToWord(1, "foo") == "1"
|
|
||||||
assert numberToWord(2, "foo") == "2"
|
|
||||||
assert numberToWord(3, "foo") == "3"
|
|
||||||
|
|
||||||
# Test out of range values
|
|
||||||
assert numberToWord(12345, "en") == "[>999]"
|
|
||||||
assert numberToWord(-2345, "en") == "[<0]"
|
|
||||||
assert numberToWord("234", "en") == "[NaN]"
|
|
||||||
|
|
||||||
# END Test testCoreTools_NumberWords
|
|
||||||
|
|||||||
Reference in New Issue
Block a user