diff --git a/.github/workflows/run-docs-build.yml b/.github/workflows/run-docs-build.yml
index 06bfa8fb..29ab62cd 100644
--- a/.github/workflows/run-docs-build.yml
+++ b/.github/workflows/run-docs-build.yml
@@ -16,7 +16,7 @@ jobs:
       matrix:
         include:
           - os: ubuntu-20.04
-            python: "3.8"
+            python: "3.9"
 
     steps:
       - uses: actions/checkout@v4
diff --git a/.github/workflows/run-tests-workflow.yml b/.github/workflows/run-tests-workflow.yml
index e39b2224..eb3873ca 100644
--- a/.github/workflows/run-tests-workflow.yml
+++ b/.github/workflows/run-tests-workflow.yml
@@ -18,13 +18,9 @@ jobs:
         include:
           # Linux
           - os: ubuntu-20.04
-            python-version: 3.8
+            python-version: 3.9
             test-env: "PyQt5~=5.12.0"
 
-          - os: ubuntu-20.04
-            python-version: 3.8
-            test-env: "PyQt5~=5.15.0"
-
           - os: ubuntu-20.04
             python-version: 3.9
             test-env: "PyQt5~=5.14.0"
@@ -53,7 +49,7 @@ jobs:
 
           # macOS
           - os: macos-12
-            python-version: 3.8
+            python-version: 3.9
             test-env: "PyQt5~=5.12.0"
 
           - os: macos-12
@@ -82,7 +78,7 @@ jobs:
 
           # Windows
           - os: windows-2019
-            python-version: 3.8
+            python-version: 3.9
             test-env: "PyQt5~=5.12.0"
 
           - os: windows-2019
diff --git a/.readthedocs.yml b/.readthedocs.yml
index 3917de26..95889b0c 100644
--- a/.readthedocs.yml
+++ b/.readthedocs.yml
@@ -3,7 +3,7 @@ version: 2
 build:
   os: ubuntu-22.04
   tools:
-    python: "3.8"
+    python: "3.9"
 
 python:
    install:
diff --git a/docs/requirements-rtd.txt b/docs/requirements-rtd.txt
index 53aff798..eaf976ae 100644
--- a/docs/requirements-rtd.txt
+++ b/docs/requirements-rtd.txt
@@ -1,7 +1,7 @@
 --only-binary PyQt5,numpy
 
 setuptools
-sphinx~=4.2.0
+sphinx~=7.4.7
 sphinx-rtd-theme
 PyQt5
 AnyQt
@@ -9,4 +9,4 @@ AnyQt
 # sphinx pins docutils version, but the installation in the RTD worker/config
 # overrides it because docutils is also in our dependencies.
 # https://docs.readthedocs.io/en/stable/faq.html#i-need-to-install-a-package-in-a-environment-with-pinned-versions
--e .
\ No newline at end of file
+-e .
diff --git a/docs/source/conf.py b/docs/source/conf.py
index cf26be9c..50919559 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -46,7 +46,7 @@
 # The suffix(es) of source filenames.
 # You can specify multiple suffix as a list of string:
 # source_suffix = ['.rst', '.md']
-source_suffix = '.rst'
+source_suffix = {'.rst': 'restructuredtext'}
 
 # The encoding of source files.
 #source_encoding = 'utf-8-sig'
@@ -73,7 +73,7 @@
 #
 # This is also used if you do content translation via gettext catalogs.
 # Usually you set "language" from the command line for these cases.
-language = None
+language = "en"
 
 # There are two options for replacing |today|: either, you set today to some
 # non-false value, then it is used:
@@ -296,4 +296,4 @@
 
 
 # Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {'https://docs.python.org/': None}
+intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
diff --git a/i18n/si/msgs.jaml b/i18n/si/msgs.jaml
index 7b3603e1..775b0fe9 100644
--- a/i18n/si/msgs.jaml
+++ b/i18n/si/msgs.jaml
@@ -365,6 +365,7 @@ application/application.py:
             -style: false
             styleHints: false
             setShowShortcutsInContextMenus: false
+            QMessageBox: false
         def `argumentParser`:
             -style: false
             -colortheme: false
@@ -3653,7 +3654,7 @@ utils/localization/__init__.py:
         i18n: false
         .json: false
         'Invalid language file ': false
-    English: null
+    English: false
     def `language_changed`:
         application/language: false
         application/last-used-language: false
@@ -3673,3 +3674,69 @@ utils/localization/__init__.py:
         def `c`:
             <string>: false
             eval: false
+utils/localization/si.py:
+    def `plsi`:
+        '|': false
+        a: false
+        i: false
+        e: false
+        ov: false
+    def `plsi_sz`:
+        {n:_}: false
+        _: false
+        1: false
+        z: false
+        zszzzzsssssssssszzzzzz: false
+        s: false
+        0: false
+        zzzssssszz: false
+    def `z_besedo`:
+        nič: false
+        m: false
+        en: false
+        enega: false
+        enemu: false
+        enem: false
+        enim: false
+        f: false
+        ena: false
+        ene: false
+        eni: false
+        eno: false
+        n: false
+        dva: false
+        dveh: false
+        dvema: false
+        dve: false
+        tri: false
+        treh: false
+        trem: false
+        tremi: false
+        štiri: false
+        štirih: false
+        štirim: false
+        štirimi: false
+        pet: false
+        petih: false
+        petim: false
+        petimi: false
+        šest: false
+        šestih: false
+        šestim: false
+        šestimi: false
+        sedem: false
+        sedmih: false
+        sedmim: false
+        sedmimi: false
+        osem: false
+        osmih: false
+        osmim: false
+        osmimi: false
+        devet: false
+        devetih: false
+        devetim: false
+        devetimi: false
+        deset: false
+        desetih: false
+        desetim: false
+        desetimi: false
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..f5bf2329
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["setuptools", "wheel", "trubar>=0.3.3"]
+build-backend = "setuptools.build_meta"
diff --git a/setup.py b/setup.py
index 8a5fe8c9..9e8cb38c 100755
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,9 @@
 #! /usr/bin/env python
+import os
+
 from setuptools import setup, find_packages
+from setuptools.command.install import install
+
 
 NAME = "orange-canvas-core"
 VERSION = "0.2.3.dev0"
@@ -60,7 +64,23 @@
     "Documentation": "https://orange-canvas-core.readthedocs.io/en/latest/",
 }
 
-PYTHON_REQUIRES = ">=3.8"
+PYTHON_REQUIRES = ">=3.9"
+
+
+class InstallMultilingualCommand(install):
+    def run(self):
+        super().run()
+        self.compile_to_multilingual()
+
+    def compile_to_multilingual(self):
+        from trubar import translate
+
+        package_dir = os.path.dirname(os.path.abspath(__file__))
+        translate(
+            "msgs.jaml",
+            source_dir=os.path.join(self.install_lib, "orangecanvas"),
+            config_file=os.path.join(package_dir, "i18n", "trubar-config.yaml"))
+
 
 if __name__ == "__main__":
     setup(
@@ -76,6 +96,9 @@
         packages=PACKAGES,
         package_data=PACKAGE_DATA,
         install_requires=INSTALL_REQUIRES,
+        cmdclass={
+            'install': InstallMultilingualCommand,
+        },
         extras_require=EXTRAS_REQUIRE,
         project_urls=PROJECT_URLS,
         python_requires=PYTHON_REQUIRES,