diff --git a/LICENSE.md b/LICENSE.md
index 7aab016207a3260e8fd41b70884fd24041090745..330581e58985051752ba469a1dacf62692fef9b1 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -641,7 +641,7 @@ the exclusion of warranty; and each file should have at least the
         GNU Affero General Public License for more details.
 
         You should have received a copy of the GNU Affero General Public License
-        along with this program.  If not, see <http://www.gnu.org/licenses/>.
+        along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 Also add information on how to contact you by electronic and paper
 mail.
@@ -657,4 +657,4 @@ the specific requirements.
 You should also get your employer (if you work as a programmer) or
 school, if any, to sign a "copyright disclaimer" for the program, if
 necessary. For more information on this, and how to apply and follow
-the GNU AGPL, see <http://www.gnu.org/licenses/>.
+the GNU AGPL, see <https://www.gnu.org/licenses/>.
diff --git a/res/app.briar.gtk.appdata.xml.in b/data/app.briar.gtk.appdata.xml.in
similarity index 80%
rename from res/app.briar.gtk.appdata.xml.in
rename to data/app.briar.gtk.appdata.xml.in
index e76d950a81644e261131abd1569cfb9c8de79443..2ec7c3580ac47c521a9786b14e34d34353d1042a 100644
--- a/res/app.briar.gtk.appdata.xml.in
+++ b/data/app.briar.gtk.appdata.xml.in
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <component type="desktop">
 	<id>app.briar.gtk.desktop</id>
-	<metadata_license>CC0-1.0</metadata_license>
+	<metadata_license>CC-BY-4.0</metadata_license>
 	<project_license>GPL-3.0-or-later</project_license>
 	<description>
 	</description>
diff --git a/res/app.briar.gtk.desktop.in b/data/app.briar.gtk.desktop.in
similarity index 86%
rename from res/app.briar.gtk.desktop.in
rename to data/app.briar.gtk.desktop.in
index f7db2e4471ff43becf9356730fa05efed1879fa3..114a89d47852270da599198180de10f1d7175fcc 100644
--- a/res/app.briar.gtk.desktop.in
+++ b/data/app.briar.gtk.desktop.in
@@ -1,5 +1,5 @@
 [Desktop Entry]
-Name=Briar GTK
+Name=Briar
 Exec=briar-gtk
 Terminal=false
 Type=Application
diff --git a/res/app.briar.gtk.gschema.xml b/data/app.briar.gtk.gschema.xml
similarity index 100%
rename from res/app.briar.gtk.gschema.xml
rename to data/app.briar.gtk.gschema.xml
diff --git a/res/meson.build b/data/meson.build
similarity index 97%
rename from res/meson.build
rename to data/meson.build
index a8cb8c3e1bb4eb5e830c8fc4ea2ccbc79c964c50..6d580f9ec84e65026085285da9726e90273b5eeb 100644
--- a/res/meson.build
+++ b/data/meson.build
@@ -44,8 +44,8 @@ pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.proje
 gnome = import('gnome')
 
 gnome.compile_resources('briar-gtk',
-  'ui/gresource.xml',
+  'ui/app.briar.gtk.gresource.xml',
   gresource_bundle: true,
   install: true,
   install_dir: pkgdatadir,
-)
\ No newline at end of file
+)
diff --git a/data/ui/app.briar.gtk.gresource.xml b/data/ui/app.briar.gtk.gresource.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8cd9fae29a6e9965fd2e37e2d3ae6f37d5277ae2
--- /dev/null
+++ b/data/ui/app.briar.gtk.gresource.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/app/briar/gtk">
+    <file compressed="true">ui/application.css</file>
+    <file compressed="true" preprocess="xml-stripblanks">ui/login.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks">ui/setup.ui</file>
+  </gresource>
+</gresources>
diff --git a/data/ui/application.css b/data/ui/application.css
new file mode 100644
index 0000000000000000000000000000000000000000..6446ebfd427495a708d3740324ba3e383dfcbbe9
--- /dev/null
+++ b/data/ui/application.css
@@ -0,0 +1,3 @@
+.test {
+  color: red;
+}
diff --git a/data/ui/login.ui b/data/ui/login.ui
new file mode 100644
index 0000000000000000000000000000000000000000..c7896cc6ed6225c3e486023906c90d080c2bed04
--- /dev/null
+++ b/data/ui/login.ui
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkGrid" id="login">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="halign">center</property>
+    <property name="valign">center</property>
+    <property name="margin_left">18</property>
+    <property name="margin_right">18</property>
+    <property name="margin_top">18</property>
+    <property name="margin_bottom">18</property>
+    <child>
+      <object class="GtkGrid" id="password_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">12</property>
+        <child>
+          <object class="GtkLabel" id="password_label">
+            <property name="visible">True</property>
+            <property name="halign">center</property>
+            <property name="label" translatable="yes">Password</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="password_entry">
+            <property name="visible">True</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="login_button">
+            <property name="visible">True</property>
+            <property name="halign">center</property>
+            <property name="label" translatable="yes">Sign in</property>
+            <signal name="clicked" handler="on_login_pressed"/>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
+
+
diff --git a/data/ui/setup.ui b/data/ui/setup.ui
new file mode 100644
index 0000000000000000000000000000000000000000..336fcfe4ed117e5d333ba511a225433278c0bcc6
--- /dev/null
+++ b/data/ui/setup.ui
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkGrid" id="setup">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="halign">center</property>
+    <property name="valign">center</property>
+    <property name="margin_left">18</property>
+    <property name="margin_right">18</property>
+    <property name="margin_top">18</property>
+    <property name="margin_bottom">18</property>
+    <child>
+      <object class="GtkGrid" id="username_grid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">12</property>
+        <child>
+          <object class="GtkLabel" id="username_label">
+            <property name="visible">True</property>
+            <property name="halign">center</property>
+            <property name="label" translatable="yes">Nickname</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="username_entry">
+            <property name="visible">True</property>
+            <property name="placeholder_text" translatable="yes">Choose your nickname</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="username_next">
+            <property name="visible">True</property>
+            <property name="halign">center</property>
+            <property name="label" translatable="yes">Next</property>
+            <signal name="clicked" handler="on_username_button_clicked"/>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkGrid" id="password_grid">
+        <property name="visible">False</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">12</property>
+        <child>
+          <object class="GtkLabel" id="password_label">
+            <property name="visible">True</property>
+            <property name="halign">center</property>
+            <property name="label" translatable="yes">Password</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="password_entry">
+            <property name="visible">True</property>
+            <property name="placeholder_text" translatable="yes">Choose your password</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="password_confirm_entry">
+            <property name="visible">True</property>
+            <property name="placeholder_text" translatable="yes">Confirm your password</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="password_next">
+            <property name="visible">True</property>
+            <property name="halign">center</property>
+            <property name="label" translatable="yes">Next</property>
+            <signal name="clicked" handler="on_password_button_clicked"/>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">3</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
+
+
diff --git a/meson.build b/meson.build
index 63ef097ca63326ba094d827ac6c2f9cb7f255a31..32d5132b448361ce36c3d18bd4ba944b90c72b31 100644
--- a/meson.build
+++ b/meson.build
@@ -6,8 +6,8 @@ project(
 
 i18n = import('i18n')
 
-subdir('res')
+subdir('data')
 subdir('src')
 subdir('po')
 
-meson.add_install_script('build-aux/meson/postinstall.py')
\ No newline at end of file
+meson.add_install_script('src/meson_post_install.py')
diff --git a/po/LINGUAS b/po/LINGUAS
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..173f97890ea02c007bd74eb217cd31447f671450 100644
--- a/po/LINGUAS
+++ b/po/LINGUAS
@@ -0,0 +1,2 @@
+de
+es
diff --git a/po/briar-gtk.pot b/po/briar-gtk.pot
new file mode 100644
index 0000000000000000000000000000000000000000..387553498505aa52a00a5bba609dd3c21b619136
--- /dev/null
+++ b/po/briar-gtk.pot
@@ -0,0 +1,46 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2019-03-24 23:15+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../data/ui/login.ui:23 ../data/ui/setup.ui:64
+msgid "Password"
+msgstr ""
+
+#: ../data/ui/login.ui:43
+msgid "Sign in"
+msgstr ""
+
+#: ../data/ui/setup.ui:23
+msgid "Nickname"
+msgstr ""
+
+#: ../data/ui/setup.ui:33
+msgid "Choose your nickname"
+msgstr ""
+
+#: ../data/ui/setup.ui:44 ../data/ui/setup.ui:95
+msgid "Next"
+msgstr ""
+
+#: ../data/ui/setup.ui:74
+msgid "Choose your password"
+msgstr ""
+
+#: ../data/ui/setup.ui:84
+msgid "Confirm your password"
+msgstr ""
diff --git a/po/de.po b/po/de.po
new file mode 100644
index 0000000000000000000000000000000000000000..d520b1760030115619e7246ba3e0049413947c93
--- /dev/null
+++ b/po/de.po
@@ -0,0 +1,27 @@
+#: ../data/ui/login.ui:23 ../data/ui/setup.ui:64
+msgid "Password"
+msgstr "Passwort"
+
+#: ../data/ui/login.ui:43
+msgid "Sign in"
+msgstr ""
+
+#: ../data/ui/setup.ui:23
+msgid "Nickname"
+msgstr "Nutzername"
+
+#: ../data/ui/setup.ui:33
+msgid "Choose your nickname"
+msgstr ""
+
+#: ../data/ui/setup.ui:44 ../data/ui/setup.ui:95
+msgid "Next"
+msgstr ""
+
+#: ../data/ui/setup.ui:74
+msgid "Choose your password"
+msgstr ""
+
+#: ../data/ui/setup.ui:84
+msgid "Confirm your password"
+msgstr ""
diff --git a/po/es.po b/po/es.po
new file mode 100644
index 0000000000000000000000000000000000000000..b5f69b2135861ceba6c8d0c3b539e138078259b2
--- /dev/null
+++ b/po/es.po
@@ -0,0 +1,27 @@
+#: ../data/ui/login.ui:23 ../data/ui/setup.ui:64
+msgid "Password"
+msgstr ""
+
+#: ../data/ui/login.ui:43
+msgid "Sign in"
+msgstr ""
+
+#: ../data/ui/setup.ui:23
+msgid "Nickname"
+msgstr ""
+
+#: ../data/ui/setup.ui:33
+msgid "Choose your nickname"
+msgstr ""
+
+#: ../data/ui/setup.ui:44 ../data/ui/setup.ui:95
+msgid "Next"
+msgstr "Seguir"
+
+#: ../data/ui/setup.ui:74
+msgid "Choose your password"
+msgstr ""
+
+#: ../data/ui/setup.ui:84
+msgid "Confirm your password"
+msgstr ""
diff --git a/po/meson.build b/po/meson.build
index f7a303ad72409efd40bdb5cd08d673dc4ff46762..14702a5e07eeac51b806c0da62c37604f5d6dd41 100644
--- a/po/meson.build
+++ b/po/meson.build
@@ -1 +1 @@
-i18n.gettext('briar-gtk', preset: 'glib')
\ No newline at end of file
+i18n.gettext('briar-gtk', preset: 'glib')
diff --git a/res/ui/gresource.xml b/res/ui/gresource.xml
deleted file mode 100644
index 3e2b68907e2f1c08c951d16c704dc6c2333ba422..0000000000000000000000000000000000000000
--- a/res/ui/gresource.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<gresources>
-  <gresource prefix="/app/briar/gtk">
-    <file preprocess="xml-stripblanks" compressed="true">ui/setup.ui</file>
-  </gresource>
-</gresources>
diff --git a/res/ui/setup.ui b/res/ui/setup.ui
deleted file mode 100644
index 59da619951063815cff4cd558a8ba79485bf584b..0000000000000000000000000000000000000000
--- a/res/ui/setup.ui
+++ /dev/null
@@ -1,121 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<interface>
-  <requires lib="gtk+" version="3.20"/>
-  <template class="BriarGtkWindow" parent="GtkApplicationWindow">
-    <property name="default-width">600</property>
-    <property name="default-height">300</property>
-    <child type="titlebar">
-      <object class="GtkHeaderBar" id="header_bar">
-        <property name="visible">True</property>
-        <property name="show-close-button">True</property>
-        <property name="title">Welcome to Briar</property>
-      </object>
-    </child>
-    <child>
-      <object class="GtkGrid">
-        <property name="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="halign">center</property>
-        <property name="valign">center</property>
-        <property name="margin_left">18</property>
-        <property name="margin_right">18</property>
-        <property name="margin_top">18</property>
-        <property name="margin_bottom">18</property>
-        <child>
-          <object class="GtkGrid" id="username_grid">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="row_spacing">6</property>
-            <property name="column_spacing">12</property>
-            <child>
-              <object class="GtkLabel" id="username_label">
-                <property name="visible">True</property>
-                <property name="halign">center</property>
-                <property name="label" translatable="yes">Nickname</property>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkEntry" id="username_entry">
-                <property name="visible">True</property>
-                <property name="placeholder_text" translatable="yes">Choose your nickname</property>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="username_next">
-                <property name="visible">True</property>
-                <property name="halign">center</property>
-                <property name="label" translatable="yes">Next</property>
-                <signal name="clicked" handler="on_username_button_clicked"/>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">2</property>
-              </packing>
-            </child>
-          </object>
-        </child>
-        <child>
-          <object class="GtkGrid" id="password_grid">
-            <property name="visible">False</property>
-            <property name="can_focus">False</property>
-            <property name="row_spacing">6</property>
-            <property name="column_spacing">12</property>
-            <child>
-              <object class="GtkLabel" id="password_label">
-                <property name="visible">True</property>
-                <property name="halign">center</property>
-                <property name="label" translatable="yes">Password</property>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkEntry" id="password_entry">
-                <property name="visible">True</property>
-                <property name="placeholder_text" translatable="yes">Choose your password</property>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkEntry" id="password_confirm_entry">
-                <property name="visible">True</property>
-                <property name="placeholder_text" translatable="yes">Confirm your password</property>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">2</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkButton" id="password_next">
-                <property name="visible">True</property>
-                <property name="halign">center</property>
-                <property name="label" translatable="yes">Next</property>
-                <signal name="clicked" handler="on_password_button_clicked"/>
-              </object>
-              <packing>
-                <property name="left_attach">1</property>
-                <property name="top_attach">3</property>
-              </packing>
-            </child>
-          </object>
-        </child>
-      </object>
-    </child>
-  </template>
-</interface>
-
-
diff --git a/src/__init__.py b/src/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/briar-gtk.in b/src/briar-gtk.in
index b64d27e396ad0d52ae0b7f1c20cef5fda7163795..e29cffa37a7081f7c221d04673d4ec0520a3672c 100755
--- a/src/briar-gtk.in
+++ b/src/briar-gtk.in
@@ -1,7 +1,5 @@
 #!@PYTHON@
 
-# briar-gtk.in
-#
 # Copyright 2019 Nico Alt
 #
 # This program is free software: you can redistribute it and/or modify
@@ -15,27 +13,34 @@
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+#
+# Initial version based on GNOME Lollypop
+# https://gitlab.gnome.org/World/lollypop/blob/1.0.2/lollypop.in
 
+import gettext
+import locale
 import os
-import sys
 import signal
-import gettext
+import sys
 
-VERSION = '@VERSION@'
 pkgdatadir = '@pkgdatadir@'
 localedir = '@localedir@'
 
 sys.path.insert(1, pkgdatadir)
 signal.signal(signal.SIGINT, signal.SIG_DFL)
-gettext.install('briar-gtk', localedir)
 
 if __name__ == '__main__':
+    locale.bindtextdomain('briar-gtk', localedir)
+    locale.textdomain('briar-gtk')
+    gettext.bindtextdomain('briar-gtk', localedir)
+    gettext.textdomain('briar-gtk')
+
     import gi
 
     from gi.repository import Gio
     resource = Gio.Resource.load(os.path.join(pkgdatadir, 'briar-gtk.gresource'))
     resource._register()
 
-    from briar_gtk import main
-    sys.exit(main.main(VERSION))
+    from briar.gtk.application import Application
+    sys.exit(Application("@VERSION@").run(sys.argv))
diff --git a/src/briar/api/api.py b/src/briar/api/api.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e613ce609f694aa4bdb18a830d383c884753978
--- /dev/null
+++ b/src/briar/api/api.py
@@ -0,0 +1,42 @@
+# Copyright (c) 2019 Nico Alt
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+from subprocess import Popen, PIPE
+
+
+class Api:
+
+    def __init__(self, headless_jar, debug=False):
+        self.headless_jar = headless_jar
+
+    def has_account(self):
+        from pathlib import Path
+        home = str(Path.home())
+        from os.path import isdir, join
+        return isdir(join(home, ".briar", "db"))
+
+    def login(self, password):
+        p = Popen(['java', '-jar', self.headless_jar, '-v'],
+                  stdin=PIPE, universal_newlines=True)
+        p.communicate(password + '\n')
+
+    def register(self, credentials):
+        p = Popen(['java', '-jar', self.headless_jar, '-v'],
+                  stdin=PIPE, universal_newlines=True)
+        p.communicate(credentials[0] + '\n' + credentials[1] +
+                      '\n' + credentials[1] + '\n')
+
+    def stop(self):
+        pass
diff --git a/src/briar/briar.py b/src/briar/api/briar.py
similarity index 97%
rename from src/briar/briar.py
rename to src/briar/api/briar.py
index 4a3c68e879fa788c1330480135e74740271cd702..5d947b37dedbc6334e4f0d8d62ba74caebac64a5 100644
--- a/src/briar/briar.py
+++ b/src/briar/api/briar.py
@@ -11,7 +11,7 @@
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #
 # Originally coming from
 # https://code.briarproject.org/grote/briar-cli-python-demo/blob/master/briar-cli.py
diff --git a/src/briar/gtk/application.py b/src/briar/gtk/application.py
new file mode 100644
index 0000000000000000000000000000000000000000..342db900e1cbf18a76e6821531718785f7aa932a
--- /dev/null
+++ b/src/briar/gtk/application.py
@@ -0,0 +1,68 @@
+# Copyright (c) 2019 Nico Alt
+# Copyright (c) 2014-2018 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+#
+# Initial version based on GNOME Lollypop
+# https://gitlab.gnome.org/World/lollypop/blob/1.0.2/lollypop/application.py
+
+from briar.api.api import Api
+
+from briar.gtk.window import Window
+
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gdk, Gio, GLib, Gtk
+
+
+class Application(Gtk.Application):
+
+    def __init__(self, version):
+        super().__init__(application_id='app.briar.gtk',
+                         flags=Gio.ApplicationFlags.FLAGS_NONE)
+        self.__version = version
+        self.set_property("register-session", True)
+        self.window = None
+        self.debug = True  # TODO: Change this in production
+        GLib.set_application_name("Briar")
+        GLib.set_prgname("briar-gtk")
+        self.api = Api('/app/briar/briar-headless.jar', self.debug)
+        self.connect("activate", self.__on_activate)
+        self.register(None)
+
+    def init(self):
+        cssProviderFile = Gio.File.new_for_uri(
+            "resource:///app/briar/gtk/ui/application.css")
+        cssProvider = Gtk.CssProvider()
+        cssProvider.load_from_file(cssProviderFile)
+        screen = Gdk.Screen.get_default()
+        styleContext = Gtk.StyleContext()
+        styleContext.add_provider_for_screen(screen, cssProvider,
+                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
+
+    def do_startup(self):
+        Gtk.Application.do_startup(self)
+        if self.window is None:
+            self.init()
+            self.window = Window()
+            self.window.show()
+
+    def quit(self):
+        self.api.stop()
+        self.window.hide()
+        Gio.Application.quit(self)
+
+    def __on_activate(self, application):
+        pass
+
diff --git a/src/briar/gtk/container.py b/src/briar/gtk/container.py
new file mode 100644
index 0000000000000000000000000000000000000000..e9770b0cc5634c5ab7d91aa26a3ddbc9526f9272
--- /dev/null
+++ b/src/briar/gtk/container.py
@@ -0,0 +1,52 @@
+# Copyright (c) 2019 Nico Alt
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+from briar.gtk.define import App
+from briar.gtk.logger import Logger
+
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+
+
+class Container(Gtk.Overlay):
+
+    def __init__(self):
+        Gtk.Overlay.__init__(self)
+        self.__setup_view()
+
+    def __setup_view(self):
+        Logger.debug("Api has account: %s", App().api.has_account())
+        self.builder = Gtk.Builder()
+        if not App().api.has_account():
+            self.builder.add_from_resource("/app/briar/gtk/ui/setup.ui")
+            self.add(self.builder.get_object("setup"))
+        else:
+            self.builder.add_from_resource("/app/briar/gtk/ui/login.ui")
+            self.add(self.builder.get_object("login"))
+        self.builder.connect_signals(self)
+
+    def on_username_button_clicked(self, button):
+        self.builder.get_object("username_grid").set_visible(False)
+        self.builder.get_object("password_grid").set_visible(True)
+        self.username = self.builder.get_object("username_entry").get_text()
+
+    def on_password_button_clicked(self, button):
+        password = self.builder.get_object("password_entry").get_text()
+        App().api.register((self.username, password))  # TODO: callback
+
+    def on_login_pressed(self, button):
+        password = self.builder.get_object("password_entry").get_text()
+        App().api.login(password)  # TODO: callback
diff --git a/src/briar/gtk/define.py b/src/briar/gtk/define.py
new file mode 100644
index 0000000000000000000000000000000000000000..509123617dc969a975f515d5f714f9175b5ef80f
--- /dev/null
+++ b/src/briar/gtk/define.py
@@ -0,0 +1,22 @@
+# Copyright (c) 2019 Nico Alt
+# Copyright (c) 2014-2018 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+#
+# Initial version based on GNOME Lollypop
+# https://gitlab.gnome.org/World/lollypop/blob/1.0.2/lollypop/define.py
+
+from gi.repository import Gio
+
+App = Gio.Application.get_default
diff --git a/src/briar/gtk/logger.py b/src/briar/gtk/logger.py
new file mode 100644
index 0000000000000000000000000000000000000000..b4a8839020181dec8c3130c480a76528a2440396
--- /dev/null
+++ b/src/briar/gtk/logger.py
@@ -0,0 +1,63 @@
+# Copyright (c) 2019 Nico Alt
+# Copyright (c) 2014-2018 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
+# Copyright (c) 2017 Bilal Elmoussaoui <bil.elmoussaoui@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+#
+# Initial version based on GNOME Lollypop
+# https://gitlab.gnome.org/World/lollypop/blob/1.0.2/lollypop/logger.py
+
+import logging
+import sys
+
+from briar.gtk.define import App
+
+
+class Logger:
+
+    FORMAT = "[%(levelname)-s] %(asctime)s %(message)s"
+    DATE = "%Y-%m-%d %H:%M:%S"
+    __log = None
+    APP = "app.briar.gtk"
+
+    @staticmethod
+    def get_default():
+        if Logger.__log is None:
+            logger = logging.getLogger(Logger.APP)
+
+            handler = logging.StreamHandler(sys.stdout)
+            formater = logging.Formatter(Logger.FORMAT, Logger.DATE)
+            handler.setFormatter(formater)
+            logger.addHandler(handler)
+            logger.setLevel(logging.DEBUG)
+
+            Logger.__log = logging.getLogger(Logger.APP)
+        return Logger.__log
+
+    @staticmethod
+    def warning(msg, *args):
+        Logger.get_default().warning(msg, *args)
+
+    @staticmethod
+    def debug(msg, *args):
+        if App().debug:
+            Logger.get_default().debug(msg, *args)
+
+    @staticmethod
+    def info(msg, *args):
+        Logger.get_default().info(msg, *args)
+
+    @staticmethod
+    def error(msg, *args):
+        Logger.get_default().error(msg, *args)
diff --git a/src/briar/gtk/window.py b/src/briar/gtk/window.py
new file mode 100644
index 0000000000000000000000000000000000000000..82448943d1a70f00287721ee77b7e0ad7ecf0aa8
--- /dev/null
+++ b/src/briar/gtk/window.py
@@ -0,0 +1,44 @@
+# Copyright (c) 2019 Nico Alt
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+from briar.gtk.container import Container
+from briar.gtk.define import App
+
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk, Gdk, GLib
+
+
+class Window(Gtk.ApplicationWindow):
+
+    def __init__(self):
+        Gtk.ApplicationWindow.__init__(self,
+                                       application=App(),
+                                       title="Briar",
+                                       icon_name="app.briar.gtk")
+        self.__setup_content()
+
+    @property
+    def container(self):
+        return self.__container
+
+    def __setup_content(self):
+        self.__container = Container()
+        self.__container.show()
+        self.__vgrid = Gtk.Grid()
+        self.__vgrid.set_orientation(Gtk.Orientation.VERTICAL)
+        self.__vgrid.show()
+        self.__vgrid.add(self.__container)
+        self.add(self.__vgrid)
diff --git a/src/main.py b/src/main.py
deleted file mode 100644
index 96e76a502208c68bb4c4a7143a5038f01f83c9d3..0000000000000000000000000000000000000000
--- a/src/main.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# main.py
-#
-# Copyright 2019 Nico Alt
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-import sys
-import gi
-
-gi.require_version('Gtk', '3.0')
-
-from gi.repository import Gtk, Gio
-
-from .setup import BriarSetupWindow
-
-
-class Application(Gtk.Application):
-    def __init__(self):
-        super().__init__(application_id='app.briar.gtk',
-                         flags=Gio.ApplicationFlags.FLAGS_NONE)
-
-    def do_activate(self):
-        win = self.props.active_window
-        if not win:
-            win = BriarSetupWindow(application=self)
-        win.present()
-
-
-def main(version):
-    app = Application()
-    return app.run(sys.argv)
diff --git a/src/meson.build b/src/meson.build
index 7faa3ba4cc0195e76d7112bcf7efe2d2d90b21b0..7d0bdbfd1054640ca027ed90c6a01ce050040b71 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -1,5 +1,5 @@
 pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
-moduledir = join_paths(pkgdatadir, 'briar_gtk')
+moduledir = join_paths(pkgdatadir, 'briar')
 
 python3 = import('python3')
 
@@ -17,11 +17,5 @@ configure_file(
   install_dir: get_option('bindir')
 )
 
-briar_gtk_sources = [
-  '__init__.py',
-  'main.py',
-  'ui/gi_composites.py',
-  'ui/setup.py',
-]
-
-install_data(briar_gtk_sources, install_dir: moduledir)
+install_subdir('briar/api', install_dir: moduledir)
+install_subdir('briar/gtk', install_dir: moduledir)
diff --git a/build-aux/meson/postinstall.py b/src/meson_post_install.py
similarity index 100%
rename from build-aux/meson/postinstall.py
rename to src/meson_post_install.py
diff --git a/src/ui/gi_composites.py b/src/ui/gi_composites.py
deleted file mode 100644
index c68402b2144a4c6dc1b846a652c8df66284bebd6..0000000000000000000000000000000000000000
--- a/src/ui/gi_composites.py
+++ /dev/null
@@ -1,268 +0,0 @@
-#
-# Copyright 2015 Dustin Spicuzza <dustin@virtualroadside.com>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
-# USA
-
-from os.path import abspath, join
-
-import inspect
-import warnings
-
-from gi.repository import Gio
-from gi.repository import GLib
-from gi.repository import GObject
-from gi.repository import Gtk
-
-__all__ = ['GtkTemplate']
-
-
-class GtkTemplateWarning(UserWarning):
-    pass
-
-
-def _connect_func(builder, obj, signal_name, handler_name,
-                  connect_object, flags, cls):
-    '''Handles GtkBuilder signal connect events'''
-
-    if connect_object is None:
-        extra = ()
-    else:
-        extra = (connect_object,)
-
-    # The handler name refers to an attribute on the template instance,
-    # so ask GtkBuilder for the template instance
-    template_inst = builder.get_object(cls.__gtype_name__)
-
-    if template_inst is None:  # This should never happen
-        errmsg = "Internal error: cannot find template instance! obj: %s; " \
-                 "signal: %s; handler: %s; connect_obj: %s; class: %s" % \
-                 (obj, signal_name, handler_name, connect_object, cls)
-        warnings.warn(errmsg, GtkTemplateWarning)
-        return
-
-    handler = getattr(template_inst, handler_name)
-
-    if flags == GObject.ConnectFlags.AFTER:
-        obj.connect_after(signal_name, handler, *extra)
-    else:
-        obj.connect(signal_name, handler, *extra)
-
-    template_inst.__connected_template_signals__.add(handler_name)
-
-
-def _register_template(cls, template_bytes):
-    '''Registers the template for the widget and hooks init_template'''
-
-    # This implementation won't work if there are nested templates, but
-    # we can't do that anyways due to PyGObject limitations so it's ok
-
-    if not hasattr(cls, 'set_template'):
-        raise TypeError("Requires PyGObject 3.13.2 or greater")
-
-    cls.set_template(template_bytes)
-
-    bound_methods = set()
-    bound_widgets = set()
-
-    # Walk the class, find marked callbacks and child attributes
-    for name in dir(cls):
-
-        o = getattr(cls, name, None)
-
-        if inspect.ismethod(o):
-            if hasattr(o, '_gtk_callback'):
-                bound_methods.add(name)
-                # Don't need to call this, as connect_func always gets called
-                # cls.bind_template_callback_full(name, o)
-        elif isinstance(o, _Child):
-            cls.bind_template_child_full(name, True, 0)
-            bound_widgets.add(name)
-
-    # Have to setup a special connect function to connect at template init
-    # because the methods are not bound yet
-    cls.set_connect_func(_connect_func, cls)
-
-    cls.__gtemplate_methods__ = bound_methods
-    cls.__gtemplate_widgets__ = bound_widgets
-
-    base_init_template = cls.init_template
-    cls.init_template = lambda s: _init_template(s, cls, base_init_template)
-
-
-def _init_template(self, cls, base_init_template):
-    '''This would be better as an override for Gtk.Widget'''
-
-    # TODO: could disallow using a metaclass.. but this is good enough
-    # .. if you disagree, feel free to fix it and issue a PR :)
-    if self.__class__ is not cls:
-        raise TypeError("Inheritance from classes with @GtkTemplate decorators"
-                        " is not allowed at this time")
-
-    connected_signals = set()
-    self.__connected_template_signals__ = connected_signals
-
-    base_init_template(self)
-
-    for name in self.__gtemplate_widgets__:
-        widget = self.get_template_child(cls, name)
-        self.__dict__[name] = widget
-
-        if widget is None:
-            # Bug: if you bind a template child, and one of them was
-            #      not present, then the whole template is broken (and
-            #      it's not currently possible for us to know which
-            #      one is broken either -- but the stderr should show
-            #      something useful with a Gtk-CRITICAL message)
-            raise AttributeError("A missing child widget was set using "
-                                 "GtkTemplate.Child and the entire "
-                                 "template is now broken (widgets: %s)" %
-                                 ', '.join(self.__gtemplate_widgets__))
-
-    for name in self.__gtemplate_methods__.difference(connected_signals):
-        errmsg = ("Signal '%s' was declared with @GtkTemplate.Callback " +
-                  "but was not present in template") % name
-        warnings.warn(errmsg, GtkTemplateWarning)
-
-
-# TODO: Make it easier for IDE to introspect this
-class _Child(object):
-    '''
-        Assign this to an attribute in your class definition and it will
-        be replaced with a widget defined in the UI file when init_template
-        is called
-    '''
-
-    __slots__ = []
-
-    @staticmethod
-    def widgets(count):
-        '''
-            Allows declaring multiple widgets with less typing::
-
-                button    \
-                label1    \
-                label2    = GtkTemplate.Child.widgets(3)
-        '''
-        return [_Child() for _ in range(count)]
-
-
-class _GtkTemplate(object):
-    '''
-        Use this class decorator to signify that a class is a composite
-        widget which will receive widgets and connect to signals as
-        defined in a UI template. You must call init_template to
-        cause the widgets/signals to be initialized from the template::
-
-            @GtkTemplate(ui='foo.ui')
-            class Foo(Gtk.Box):
-
-                def __init__(self):
-                    super(Foo, self).__init__()
-                    self.init_template()
-
-        The 'ui' parameter can either be a file path or a GResource resource
-        path::
-
-            @GtkTemplate(ui='/org/example/foo.ui')
-            class Foo(Gtk.Box):
-                pass
-
-        To connect a signal to a method on your instance, do::
-
-            @GtkTemplate.Callback
-            def on_thing_happened(self, widget):
-                pass
-
-        To create a child attribute that is retrieved from your template,
-        add this to your class definition::
-
-            @GtkTemplate(ui='foo.ui')
-            class Foo(Gtk.Box):
-
-                widget = GtkTemplate.Child()
-
-
-        Note: This is implemented as a class decorator, but if it were
-        included with PyGI I suspect it might be better to do this
-        in the GObject metaclass (or similar) so that init_template
-        can be called automatically instead of forcing the user to do it.
-
-        .. note:: Due to limitations in PyGObject, you may not inherit from
-                  python objects that use the GtkTemplate decorator.
-    '''
-
-    __ui_path__ = None
-
-    @staticmethod
-    def Callback(f):
-        '''
-            Decorator that designates a method to be attached to a signal from
-            the template
-        '''
-        f._gtk_callback = True
-        return f
-
-    Child = _Child
-
-    @staticmethod
-    def set_ui_path(*path):
-        '''
-            If using file paths instead of resources, call this *before*
-            loading anything that uses GtkTemplate, or it will fail to load
-            your template file
-
-            :param path: one or more path elements, will be joined together
-                         to create the final path
-
-            TODO: Alternatively, could wait until first class instantiation
-                  before registering templates? Would need a metaclass...
-        '''
-        _GtkTemplate.__ui_path__ = abspath(join(*path))
-
-    def __init__(self, ui):
-        self.ui = ui
-
-    def __call__(self, cls):
-
-        if not issubclass(cls, Gtk.Widget):
-            raise TypeError("Can only use @GtkTemplate on Widgets")
-
-        # Nested templates don't work
-        if hasattr(cls, '__gtemplate_methods__'):
-            raise TypeError("Cannot nest template classes")
-
-        # Load the template either from a resource path or a file
-        # - Prefer the resource path first
-
-        try:
-            template_bytes = \
-             Gio.resources_lookup_data(self.ui, Gio.ResourceLookupFlags.NONE)
-        except GLib.GError:
-            ui = self.ui
-            if isinstance(ui, (list, tuple)):
-                ui = join(ui)
-
-            if _GtkTemplate.__ui_path__ is not None:
-                ui = join(_GtkTemplate.__ui_path__, ui)
-
-            with open(ui, 'rb') as fp:
-                template_bytes = GLib.Bytes.new(fp.read())
-
-        _register_template(cls, template_bytes)
-        return cls
-
-
-GtkTemplate = _GtkTemplate
diff --git a/src/ui/setup.py b/src/ui/setup.py
deleted file mode 100644
index 58e37e773672d764015fc85f3aee3cab82da3b77..0000000000000000000000000000000000000000
--- a/src/ui/setup.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# window.py
-#
-# Copyright 2019 Nico Alt
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from gi.repository import Gtk
-from .gi_composites import GtkTemplate
-
-
-@GtkTemplate(ui='/app/briar/gtk/ui/setup.ui')
-class BriarSetupWindow(Gtk.ApplicationWindow):
-    __gtype_name__ = 'BriarGtkWindow'
-
-    username_grid = GtkTemplate.Child()
-    username_entry = GtkTemplate.Child()
-
-    password_grid = GtkTemplate.Child()
-    password_entry = GtkTemplate.Child()
-    password_confirm_entry = GtkTemplate.Child()
-
-    def __init__(self, **kwargs):
-        super().__init__(**kwargs)
-        self.init_template()
-
-    def on_username_button_clicked(self, button):
-        self.username_grid.set_visible(False)
-        self.password_grid.set_visible(True)
-        self.username = self.username_entry.get_text()
-
-    def on_password_button_clicked(self, button):
-        self.password = self.password_entry.get_text()
diff --git a/tools/generate_data.sh b/tools/generate_data.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4a65b4ee83168954fec51f4ffabda6999973a003
--- /dev/null
+++ b/tools/generate_data.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+# Initial version from GNOME Lollypop
+# https://gitlab.gnome.org/World/lollypop/blob/1.0.2/generate_data.sh
+
+function generate_resource()
+{
+    echo '<?xml version="1.0" encoding="UTF-8"?>'
+    echo '<gresources>'
+    echo '  <gresource prefix="/app/briar/gtk">'
+    for file in data/ui/*.css
+    do
+        echo -n '    <file compressed="true">'
+        echo -n 'ui/'
+        echo -n $(basename $file)
+        echo '</file>'
+    done
+    for file in data/ui/*.ui
+    do
+        echo -n '    <file compressed="true" preprocess="xml-stripblanks">'
+        echo -n 'ui/'
+        echo -n $(basename $file)
+        echo '</file>'
+    done
+    echo '  </gresource>'
+    echo '</gresources>'
+}
+
+function generate_po()
+{
+    cd po
+    # git pull https://www.transifex.com/otf/briar/
+    >briar-gtk.pot
+    for file in ../data/app.briar.gtk.gschema.xml ../data/ui/*.ui $(find "../src/briar" -name '*.py');
+    do
+        xgettext --from-code=UTF-8 -j $file -o briar-gtk.pot
+    done
+    >LINGUAS
+    for po in *.po
+    do
+        msgmerge -N $po briar-gtk.pot > /tmp/$$language_new.po
+        mv /tmp/$$language_new.po $po
+        language=${po%.po}
+        echo $language >>LINGUAS
+    done
+}
+
+generate_resource > data/ui/app.briar.gtk.gresource.xml
+generate_po