novelWriter 2.1.1__py3-none-any.whl → 2.2rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/METADATA +3 -3
  2. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/RECORD +105 -76
  3. novelwriter/__init__.py +6 -24
  4. novelwriter/assets/i18n/project_de_DE.json +10 -0
  5. novelwriter/assets/i18n/project_en_GB.json +11 -0
  6. novelwriter/assets/i18n/project_en_US.json +10 -0
  7. novelwriter/assets/i18n/project_ja_JP.json +11 -1
  8. novelwriter/assets/i18n/project_nb_NO.json +10 -0
  9. novelwriter/assets/i18n/project_nn_NO.json +10 -0
  10. novelwriter/assets/icons/novelwriter.ico +0 -0
  11. novelwriter/assets/icons/novelwriter.svg +8 -183
  12. novelwriter/assets/icons/typicons_dark/icons.conf +17 -2
  13. novelwriter/assets/icons/typicons_dark/nw_deco-h2-narrow.svg +4 -0
  14. novelwriter/assets/icons/typicons_dark/nw_deco-h3-narrow.svg +4 -0
  15. novelwriter/assets/icons/typicons_dark/nw_deco-h4-narrow.svg +4 -0
  16. novelwriter/assets/icons/typicons_dark/nw_deco-note.svg +4 -0
  17. novelwriter/assets/icons/typicons_dark/nw_panel.svg +4 -0
  18. novelwriter/assets/icons/typicons_dark/nw_tb-bold.svg +4 -0
  19. novelwriter/assets/icons/typicons_dark/nw_tb-italic.svg +4 -0
  20. novelwriter/assets/icons/typicons_dark/nw_tb-markdown.svg +8 -0
  21. novelwriter/assets/icons/typicons_dark/nw_tb-shortcode.svg +8 -0
  22. novelwriter/assets/icons/typicons_dark/nw_tb-strike.svg +4 -0
  23. novelwriter/assets/icons/typicons_dark/nw_tb-subscript.svg +5 -0
  24. novelwriter/assets/icons/typicons_dark/nw_tb-superscript.svg +5 -0
  25. novelwriter/assets/icons/typicons_dark/nw_tb-underline.svg +5 -0
  26. novelwriter/assets/icons/typicons_dark/typ_eye.svg +4 -0
  27. novelwriter/assets/icons/typicons_dark/typ_th-dot-menu.svg +4 -0
  28. novelwriter/assets/icons/typicons_light/icons.conf +17 -2
  29. novelwriter/assets/icons/typicons_light/nw_deco-h2-narrow.svg +4 -0
  30. novelwriter/assets/icons/typicons_light/nw_deco-h3-narrow.svg +4 -0
  31. novelwriter/assets/icons/typicons_light/nw_deco-h4-narrow.svg +4 -0
  32. novelwriter/assets/icons/typicons_light/nw_deco-note.svg +4 -0
  33. novelwriter/assets/icons/typicons_light/nw_panel.svg +4 -0
  34. novelwriter/assets/icons/typicons_light/nw_tb-bold.svg +4 -0
  35. novelwriter/assets/icons/typicons_light/nw_tb-italic.svg +4 -0
  36. novelwriter/assets/icons/typicons_light/nw_tb-markdown.svg +8 -0
  37. novelwriter/assets/icons/typicons_light/nw_tb-shortcode.svg +8 -0
  38. novelwriter/assets/icons/typicons_light/nw_tb-strike.svg +4 -0
  39. novelwriter/assets/icons/typicons_light/nw_tb-subscript.svg +5 -0
  40. novelwriter/assets/icons/typicons_light/nw_tb-superscript.svg +5 -0
  41. novelwriter/assets/icons/typicons_light/nw_tb-underline.svg +5 -0
  42. novelwriter/assets/icons/typicons_light/typ_eye.svg +4 -0
  43. novelwriter/assets/icons/typicons_light/typ_th-dot-menu.svg +4 -0
  44. novelwriter/assets/icons/x-novelwriter-project.ico +0 -0
  45. novelwriter/assets/icons/x-novelwriter-project.svg +7 -206
  46. novelwriter/assets/manual.pdf +0 -0
  47. novelwriter/assets/sample.zip +0 -0
  48. novelwriter/assets/syntax/default_dark.conf +1 -0
  49. novelwriter/assets/syntax/default_light.conf +1 -0
  50. novelwriter/assets/syntax/grey_dark.conf +1 -0
  51. novelwriter/assets/syntax/grey_light.conf +1 -0
  52. novelwriter/assets/syntax/light_owl.conf +1 -0
  53. novelwriter/assets/syntax/night_owl.conf +1 -0
  54. novelwriter/assets/syntax/solarized_dark.conf +1 -0
  55. novelwriter/assets/syntax/solarized_light.conf +1 -0
  56. novelwriter/assets/syntax/tomorrow.conf +1 -0
  57. novelwriter/assets/syntax/tomorrow_night.conf +1 -0
  58. novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
  59. novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
  60. novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
  61. novelwriter/assets/text/credits_en.htm +7 -0
  62. novelwriter/assets/text/release_notes.htm +7 -37
  63. novelwriter/common.py +22 -1
  64. novelwriter/config.py +27 -42
  65. novelwriter/constants.py +45 -7
  66. novelwriter/core/buildsettings.py +40 -24
  67. novelwriter/core/coretools.py +8 -1
  68. novelwriter/core/docbuild.py +2 -6
  69. novelwriter/core/index.py +264 -175
  70. novelwriter/core/options.py +8 -3
  71. novelwriter/core/project.py +2 -2
  72. novelwriter/core/projectdata.py +3 -3
  73. novelwriter/core/tohtml.py +60 -59
  74. novelwriter/core/tokenizer.py +110 -70
  75. novelwriter/core/tomd.py +51 -38
  76. novelwriter/core/toodt.py +184 -147
  77. novelwriter/dialogs/preferences.py +75 -106
  78. novelwriter/dialogs/projsettings.py +101 -110
  79. novelwriter/dialogs/updates.py +25 -14
  80. novelwriter/enum.py +28 -3
  81. novelwriter/extensions/novelselector.py +1 -1
  82. novelwriter/gui/doceditor.py +1345 -1235
  83. novelwriter/gui/dochighlight.py +98 -62
  84. novelwriter/gui/docviewer.py +151 -340
  85. novelwriter/gui/docviewerpanel.py +457 -0
  86. novelwriter/gui/editordocument.py +126 -0
  87. novelwriter/gui/mainmenu.py +350 -300
  88. novelwriter/gui/noveltree.py +101 -125
  89. novelwriter/gui/outline.py +154 -171
  90. novelwriter/gui/projtree.py +480 -380
  91. novelwriter/gui/sidebar.py +106 -75
  92. novelwriter/gui/statusbar.py +1 -1
  93. novelwriter/gui/theme.py +114 -75
  94. novelwriter/guimain.py +353 -254
  95. novelwriter/shared.py +36 -3
  96. novelwriter/tools/dictionaries.py +268 -0
  97. novelwriter/tools/manusbuild.py +17 -6
  98. novelwriter/tools/manuscript.py +11 -3
  99. novelwriter/tools/manussettings.py +0 -14
  100. novelwriter/tools/projwizard.py +16 -2
  101. novelwriter/tools/writingstats.py +1 -1
  102. novelwriter/assets/icons/typicons_dark/typ_at.svg +0 -4
  103. novelwriter/assets/icons/typicons_dark/typ_th-menu.svg +0 -4
  104. novelwriter/assets/icons/typicons_light/typ_at.svg +0 -4
  105. novelwriter/assets/icons/typicons_light/typ_th-menu.svg +0 -4
  106. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/LICENSE.md +0 -0
  107. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/WHEEL +0 -0
  108. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/entry_points.txt +0 -0
  109. {novelWriter-2.1.1.dist-info → novelWriter-2.2rc1.dist-info}/top_level.txt +0 -0
novelwriter/constants.py CHANGED
@@ -23,6 +23,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
23
23
  """
24
24
  from __future__ import annotations
25
25
 
26
+ import re
27
+
26
28
  from PyQt5.QtCore import QCoreApplication, QT_TRANSLATE_NOOP
27
29
 
28
30
  from novelwriter.enum import nwBuildFmt, nwItemClass, nwItemLayout, nwOutline
@@ -40,10 +42,6 @@ class nwConst:
40
42
  FMT_FSTAMP = "%Y-%m-%d %H.%M.%S" # FileName safe format
41
43
  FMT_DSTAMP = "%Y-%m-%d" # Date only format
42
44
 
43
- # Various Hard Limits
44
- MAX_DOCSIZE = 5000000 # Maximum size of a single document
45
- MAX_BUILDSIZE = 10000000 # Maximum size of a project build
46
-
47
45
  # URLs
48
46
  URL_WEB = "https://novelwriter.io"
49
47
  URL_DOCS = "https://docs.novelwriter.io"
@@ -52,6 +50,9 @@ class nwConst:
52
50
  URL_HELP = "https://github.com/vkbo/novelWriter/discussions"
53
51
  URL_RELEASE = "https://github.com/vkbo/novelWriter/releases/latest"
54
52
 
53
+ # Requests
54
+ USER_AGENT = "Mozilla/5.0 (compatible; novelWriter (Python))"
55
+
55
56
  # Gui Settings
56
57
  STATUS_MSG_TIMEOUT = 15000 # milliseconds
57
58
 
@@ -63,10 +64,33 @@ class nwRegEx:
63
64
  FMT_EI = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
64
65
  FMT_EB = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
65
66
  FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
67
+ FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:i|b|s|u|sup|sub)\])"
68
+ FMT_SV = r"(?<!\\)(\[(?i)(?:fn|footnote):)(.+?)(?<!\\)(\])"
69
+
70
+ # Pre-Compiled RegEx
71
+ RX_SC = re.compile(FMT_SC)
66
72
 
67
73
  # END Class nwRegEx
68
74
 
69
75
 
76
+ class nwShortcode:
77
+
78
+ BOLD_O = "[b]"
79
+ BOLD_C = "[/b]"
80
+ ITALIC_O = "[i]"
81
+ ITALIC_C = "[/i]"
82
+ STRIKE_O = "[s]"
83
+ STRIKE_C = "[/s]"
84
+ ULINE_O = "[u]"
85
+ ULINE_C = "[/u]"
86
+ SUP_O = "[sup]"
87
+ SUP_C = "[/sup]"
88
+ SUB_O = "[sub]"
89
+ SUB_C = "[/sub]"
90
+
91
+ # END Class nwShortcode
92
+
93
+
70
94
  class nwHeaders:
71
95
 
72
96
  H_VALID = ("H0", "H1", "H2", "H3", "H4")
@@ -132,6 +156,21 @@ class nwKeyWords:
132
156
  # END Class nwKeyWords
133
157
 
134
158
 
159
+ class nwLists:
160
+
161
+ USER_CLASSES = [
162
+ nwItemClass.CHARACTER,
163
+ nwItemClass.PLOT,
164
+ nwItemClass.WORLD,
165
+ nwItemClass.TIMELINE,
166
+ nwItemClass.OBJECT,
167
+ nwItemClass.ENTITY,
168
+ nwItemClass.CUSTOM,
169
+ ]
170
+
171
+ # END Class nwLists
172
+
173
+
135
174
  class nwLabels:
136
175
 
137
176
  CLASS_NAME = {
@@ -200,8 +239,8 @@ class nwLabels:
200
239
  nwOutline.FOCUS: QT_TRANSLATE_NOOP("Constant", "Focus"),
201
240
  nwOutline.CHAR: KEY_NAME[nwKeyWords.CHAR_KEY],
202
241
  nwOutline.PLOT: KEY_NAME[nwKeyWords.PLOT_KEY],
203
- nwOutline.TIME: KEY_NAME[nwKeyWords.TIME_KEY],
204
242
  nwOutline.WORLD: KEY_NAME[nwKeyWords.WORLD_KEY],
243
+ nwOutline.TIME: KEY_NAME[nwKeyWords.TIME_KEY],
205
244
  nwOutline.OBJECT: KEY_NAME[nwKeyWords.OBJECT_KEY],
206
245
  nwOutline.ENTITY: KEY_NAME[nwKeyWords.ENTITY_KEY],
207
246
  nwOutline.CUSTOM: KEY_NAME[nwKeyWords.CUSTOM_KEY],
@@ -306,8 +345,7 @@ class nwQuotes:
306
345
 
307
346
 
308
347
  class nwUnicode:
309
- """Supported unicode character constants and their HTML equivalents.
310
- """
348
+ """Supported unicode character constants and their HTML equivalents."""
311
349
  # Unicode Constants
312
350
  # =================
313
351
 
@@ -64,7 +64,6 @@ SETTINGS_TEMPLATE = {
64
64
  "text.includeKeywords": (bool, False),
65
65
  "text.includeBodyText": (bool, True),
66
66
  "text.addNoteHeadings": (bool, True),
67
- "format.buildLang": (str, "en_GB"),
68
67
  "format.textFont": (str, CONFIG.textFont),
69
68
  "format.textSize": (int, 12),
70
69
  "format.lineHeight": (float, 1.15, 0.75, 3.0),
@@ -107,7 +106,6 @@ SETTINGS_LABELS = {
107
106
  "text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"),
108
107
 
109
108
  "format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"),
110
- "format.buildLang": QT_TRANSLATE_NOOP("Builds", "Language"),
111
109
  "format.textFont": QT_TRANSLATE_NOOP("Builds", "Font Family"),
112
110
  "format.textSize": QT_TRANSLATE_NOOP("Builds", "Font Size"),
113
111
  "format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"),
@@ -158,6 +156,7 @@ class BuildSettings:
158
156
  self._uuid = str(uuid.uuid4())
159
157
  self._path = Path.home()
160
158
  self._build = ""
159
+ self._order = 0
161
160
  self._format = nwBuildFmt.ODT
162
161
  self._skipRoot = set()
163
162
  self._excluded = set()
@@ -166,20 +165,32 @@ class BuildSettings:
166
165
  self._changed = False
167
166
  return
168
167
 
168
+ @classmethod
169
+ def fromDict(cls, data: dict) -> BuildSettings:
170
+ """Create a build settings object from a dict."""
171
+ cls = BuildSettings()
172
+ cls.unpack(data)
173
+ return cls
174
+
169
175
  ##
170
176
  # Properties
171
177
  ##
172
178
 
173
179
  @property
174
180
  def name(self) -> str:
175
- """The build name."""
181
+ """Return the build name."""
176
182
  return self._name
177
183
 
178
184
  @property
179
185
  def buildID(self) -> str:
180
- """The build ID as a UUID."""
186
+ """Return the build ID as a UUID."""
181
187
  return self._uuid
182
188
 
189
+ @property
190
+ def order(self) -> int:
191
+ """Return the build order."""
192
+ return self._order
193
+
183
194
  @property
184
195
  def lastPath(self) -> Path:
185
196
  """The last used build path."""
@@ -253,6 +264,12 @@ class BuildSettings:
253
264
  self._uuid = value
254
265
  return
255
266
 
267
+ def setOrder(self, value: int) -> None:
268
+ """Set the build order."""
269
+ if isinstance(value, int):
270
+ self._order = value
271
+ return
272
+
256
273
  def setLastPath(self, path: Path | str | None) -> None:
257
274
  """Set the last used build path."""
258
275
  if isinstance(path, str):
@@ -332,7 +349,7 @@ class BuildSettings:
332
349
  def buildItemFilter(
333
350
  self, project: NWProject, withRoots: bool = False
334
351
  ) -> dict[str, tuple[bool, FilterMode]]:
335
- """Return a dictionary of item handles with filter decissions
352
+ """Return a dictionary of item handles with filter decisions
336
353
  applied.
337
354
  """
338
355
  result: dict[str, tuple[bool, FilterMode]] = {}
@@ -400,6 +417,7 @@ class BuildSettings:
400
417
  "uuid": self._uuid,
401
418
  "path": str(self._path),
402
419
  "build": self._build,
420
+ "order": self._order,
403
421
  "format": self._format.name,
404
422
  "settings": self._settings.copy(),
405
423
  "content": {
@@ -411,14 +429,15 @@ class BuildSettings:
411
429
 
412
430
  def unpack(self, data: dict) -> None:
413
431
  """Unpack a dictionary and populate the class."""
432
+ content = data.get("content", {})
414
433
  settings = data.get("settings", {})
415
- content = data.get("content", {})
416
434
  included = content.get("included", [])
417
435
  excluded = content.get("excluded", [])
418
436
  skipRoot = content.get("skipRoot", [])
419
437
 
420
438
  self.setName(data.get("name", ""))
421
439
  self.setBuildID(data.get("uuid", ""))
440
+ self.setOrder(data.get("order", 0))
422
441
  self.setLastPath(data.get("path", None))
423
442
  self.setLastBuildName(data.get("build", ""))
424
443
 
@@ -455,9 +474,9 @@ class BuildCollection:
455
474
 
456
475
  def __init__(self, project: NWProject) -> None:
457
476
  self._project = project
458
- self._builds = {}
459
477
  self._lastBuild = ""
460
478
  self._defaultBuild = ""
479
+ self._builds: dict[str, BuildSettings] = {}
461
480
  self._loadCollection()
462
481
  return
463
482
 
@@ -485,21 +504,19 @@ class BuildCollection:
485
504
 
486
505
  def getBuild(self, buildID: str) -> BuildSettings | None:
487
506
  """Get a specific build settings object."""
488
- if buildID not in self._builds:
489
- return None
490
- build = BuildSettings()
491
- build.unpack(self._builds[buildID])
492
- return build
507
+ return self._builds.get(buildID, None)
493
508
 
494
509
  ##
495
510
  # Setters
496
511
  ##
497
512
 
498
- def setLastBuild(self, buildID: str) -> None:
513
+ def setBuildsState(self, lastBuild: str, order: list[str]) -> None:
499
514
  """Set the last active build id."""
500
- if buildID != self._lastBuild:
501
- self._lastBuild = buildID
502
- self._saveCollection()
515
+ for i, key in enumerate(order):
516
+ if build := self._builds.get(key):
517
+ build.setOrder(i)
518
+ self._lastBuild = lastBuild
519
+ self._saveCollection()
503
520
  return
504
521
 
505
522
  def setDefaultBuild(self, buildID: str) -> None:
@@ -512,8 +529,7 @@ class BuildCollection:
512
529
  def setBuild(self, build: BuildSettings) -> None:
513
530
  """Set build settings data in the collection."""
514
531
  if isinstance(build, BuildSettings):
515
- buildID = build.buildID
516
- self._builds[buildID] = build.pack()
532
+ self._builds[build.buildID] = build
517
533
  self._saveCollection()
518
534
  return
519
535
 
@@ -522,15 +538,15 @@ class BuildCollection:
522
538
  ##
523
539
 
524
540
  def removeBuild(self, buildID: str) -> None:
525
- """Remove the a build from the collection."""
541
+ """Remove a build from the collection."""
526
542
  self._builds.pop(buildID, None)
527
543
  self._saveCollection()
528
544
  return
529
545
 
530
546
  def builds(self) -> Iterable[tuple[str, str]]:
531
547
  """Iterate over all available builds."""
532
- for buildID in self._builds:
533
- yield buildID, self._builds[buildID].get("name", "")
548
+ for buildID, build in sorted(self._builds.items(), key=lambda x: x[1].order):
549
+ yield buildID, build.name
534
550
  return
535
551
 
536
552
  ##
@@ -569,7 +585,7 @@ class BuildCollection:
569
585
  elif key == "defaultBuild":
570
586
  self._defaultBuild = str(entry)
571
587
  elif isinstance(entry, dict):
572
- self._builds[key] = entry
588
+ self._builds[key] = BuildSettings.fromDict(entry)
573
589
 
574
590
  return True
575
591
 
@@ -581,11 +597,11 @@ class BuildCollection:
581
597
 
582
598
  logger.debug("Saving builds file")
583
599
  try:
584
- data = {
600
+ data: dict[str, str | dict] = {
585
601
  "lastBuild": self._lastBuild,
586
602
  "defaultBuild": self._defaultBuild,
587
603
  }
588
- data.update(self._builds)
604
+ data.update({k: b.pack() for k, b in self._builds.items()})
589
605
  with open(buildsFile, mode="w+", encoding="utf-8") as outFile:
590
606
  outFile.write(jsonEncode({"novelWriter.builds": data}, nmax=4))
591
607
  except Exception:
@@ -353,11 +353,13 @@ class ProjectBuilder:
353
353
  projName = data.get("projName", lblNewProject)
354
354
  projTitle = data.get("projTitle", lblNewProject)
355
355
  projAuthor = data.get("projAuthor", "")
356
+ projLang = data.get("projLang", "en_GB")
356
357
 
357
358
  project.data.setUuid(None)
358
359
  project.data.setName(projName)
359
360
  project.data.setTitle(projTitle)
360
361
  project.data.setAuthor(projAuthor)
362
+ project.data.setLanguage(projLang)
361
363
  project.setDefaultStatusImport()
362
364
  project.session.startSession()
363
365
 
@@ -404,6 +406,7 @@ class ProjectBuilder:
404
406
 
405
407
  chSynop = self.tr("Summary of the chapter.")
406
408
  scSynop = self.tr("Summary of the scene.")
409
+ bfNote = self.tr("A short description.")
407
410
 
408
411
  # Create chapters
409
412
  if numChapters > 0:
@@ -444,7 +447,11 @@ class ProjectBuilder:
444
447
  aHandle = project.newFile(noteTitles[newRoot], rHandle)
445
448
  ntTag = simplified(noteTitles[newRoot]).replace(" ", "")
446
449
  aDoc = project.storage.getDocument(aHandle)
447
- aDoc.writeDocument(f"# {noteTitles[newRoot]}\n\n@tag: {ntTag}\n\n")
450
+ aDoc.writeDocument(
451
+ f"# {noteTitles[newRoot]}\n\n"
452
+ f"@tag: {ntTag}\n\n"
453
+ f"% Short: {bfNote}\n\n"
454
+ )
448
455
 
449
456
  # Also add the archive and trash folders
450
457
  project.newRoot(nwItemClass.ARCHIVE)
@@ -184,7 +184,7 @@ class NWBuildDocument:
184
184
  filtered = self._setupBuild(makeObj)
185
185
 
186
186
  if extendedMd:
187
- makeObj.setGitHubMarkdown()
187
+ makeObj.setExtendedMarkdown()
188
188
  else:
189
189
  makeObj.setStandardMarkdown()
190
190
 
@@ -248,13 +248,9 @@ class NWBuildDocument:
248
248
  def _setupBuild(self, bldObj: Tokenizer) -> dict:
249
249
  """Configure the build object."""
250
250
  # Get Settings
251
- buildLang = self._build.getStr("format.buildLang")
252
251
  textFont = self._build.getStr("format.textFont")
253
252
  textSize = self._build.getInt("format.textSize")
254
253
 
255
- # The language lookup dict is reloaded if needed
256
- self._project.setProjectLang(buildLang)
257
-
258
254
  fontFamily = textFont or CONFIG.textFont
259
255
  bldFont = QFont(fontFamily, textSize)
260
256
  fontInfo = QFontInfo(bldFont)
@@ -287,7 +283,7 @@ class NWBuildDocument:
287
283
 
288
284
  if isinstance(bldObj, ToOdt):
289
285
  bldObj.setColourHeaders(self._build.getBool("odt.addColours"))
290
- bldObj.setLanguage(buildLang)
286
+ bldObj.setLanguage(self._project.data.language)
291
287
 
292
288
  scale = nwLabels.UNIT_SCALE.get(self._build.getStr("format.pageUnit"), 1.0)
293
289
  pW, pH = nwLabels.PAPER_SIZE.get(self._build.getStr("format.pageSize"), (-1.0, -1.0))