diff --git a/.gitignore b/.gitignore
index a36741b7..50425e02 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,7 @@ python-for-android/dists/kolibri/src/main/AndroidManifest.xml
python-for-android/dists/kolibri/webview_includes
python-for-android/dists/kolibri/*.*
python-for-android/dists/kolibri/gradlew
+python-for-android/dists/kolibri/src/main/res/*/html_content.xml
# File format for signing key
*.jks
diff --git a/Makefile b/Makefile
index 7d649433..d3aab169 100644
--- a/Makefile
+++ b/Makefile
@@ -72,6 +72,10 @@ src/kolibri: clean
unzip -qo "whl/kolibri*.whl" "kolibri/*" -x "kolibri/dist/py2only*" -d src/
# patch Django to allow migrations to be pyc files, as p4a compiles and deletes the originals
sed -i 's/if name.endswith(".py"):/if name.endswith(".py") or name.endswith(".pyc"):/g' src/kolibri/dist/django/db/migrations/loader.py
+ $(MAKE) create-strings
+
+create-strings:
+ python scripts/create_strings.py
# Checks to see if we have any uncommitted changes in the Android project
# use this to prevent losing uncommitted changes when updating or rebuilding the P4A project
diff --git a/python-for-android/dists/kolibri/src/main/assets/_load.html b/python-for-android/dists/kolibri/src/main/assets/_load.html
deleted file mode 100644
index d29f561e..00000000
--- a/python-for-android/dists/kolibri/src/main/assets/_load.html
+++ /dev/null
@@ -1,302 +0,0 @@
-
-
-
-
-
-
- Kolibri is starting...
-
-
-
-
-
-
-
-
-
-
Starting Kolibri
-
Please wait; this may take some time.
-
-
-
-
diff --git a/python-for-android/dists/kolibri/src/main/assets/_loading_style.css b/python-for-android/dists/kolibri/src/main/assets/_loading_style.css
deleted file mode 100644
index 68338551..00000000
--- a/python-for-android/dists/kolibri/src/main/assets/_loading_style.css
+++ /dev/null
@@ -1,78 +0,0 @@
-
-h1 {
- font-size: 30px;
- color: blue;
- font-weight: bold;
- text-align:center;
-}
-
-h2 {
- text-align:center;
-}
-
-button {
- margin-left: auto;
- margin-right: auto;
- display: block;
- margin-top: 50px;
- font-size: 30px;
-}
-
-
-/* Loader from http://projects.lukehaas.me/css-loaders/#load1 */
-
-.loader,
-.loader:before,
-.loader:after {
- background: #aaaaff;
- -webkit-animation: load1 1s infinite ease-in-out;
- animation: load1 1s infinite ease-in-out;
- width: 1em;
- height: 4em;
-}
-.loader:before,
-.loader:after {
- position: absolute;
- top: 0;
- content: '';
-}
-.loader:before {
- left: -1.5em;
-}
-.loader {
- text-indent: -9999em;
- margin: 8em auto;
- position: relative;
- font-size: 11px;
- -webkit-animation-delay: -0.16s;
- animation-delay: -0.16s;
-}
-.loader:after {
- left: 1.5em;
- -webkit-animation-delay: -0.32s;
- animation-delay: -0.32s;
-}
-@-webkit-keyframes load1 {
- 0%,
- 80%,
- 100% {
- box-shadow: 0 0 #aaaaff;
- height: 4em;
- }
- 40% {
- box-shadow: 0 -2em #aaaaff;
- height: 5em;
- }
-}
-@keyframes load1 {
- 0%,
- 80%,
- 100% {
- box-shadow: 0 0 #aaaaff;
- height: 4em;
- }
- 40% {
- box-shadow: 0 -2em #aaaaff;
- height: 5em;
- }
-}
diff --git a/python-for-android/dists/kolibri/src/main/java/org/kivy/android/PythonActivity.java b/python-for-android/dists/kolibri/src/main/java/org/kivy/android/PythonActivity.java
index 3c887531..ac5859c1 100644
--- a/python-for-android/dists/kolibri/src/main/java/org/kivy/android/PythonActivity.java
+++ b/python-for-android/dists/kolibri/src/main/java/org/kivy/android/PythonActivity.java
@@ -167,7 +167,7 @@ public void onClick(DialogInterface dialog,int id) {
mWebView = new WebView(PythonActivity.mActivity);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setDomStorageEnabled(true);
- mWebView.loadUrl("file:///android_asset/_load.html");
+ mWebView.loadData(PythonActivity.mActivity.getString(R.string.loading_page_html), "text/html", "UTF-8");
mWebView.getSettings().setAllowFileAccessFromFileURLs(true);
mWebView.getSettings().setAllowUniversalAccessFromFileURLs(true);
mWebView.getSettings().setMediaPlaybackRequiresUserGesture(false);
diff --git a/scripts/create_strings.py b/scripts/create_strings.py
new file mode 100644
index 00000000..10f3865d
--- /dev/null
+++ b/scripts/create_strings.py
@@ -0,0 +1,99 @@
+"""
+Tooling for generating i18n strings using Kolibri's translation machinery.
+"""
+import os
+import sys
+import tempfile
+
+
+# By default we will map the locale code to e.g. "en-us" to "en-rUS"
+# except for mapping specified below.
+
+locale_code_map = {
+ "es-419": "b+es+419",
+ "zh-hans": "zh",
+}
+
+XML_TEMPLATE = """
+
+
+
+"""
+
+# The language code that will be used for the non-prefixed values folder
+DEFAULT_LANGUAGE = "en"
+
+
+def generate_loading_pages(output_dir):
+ """
+ Run the Django management command to generate the loading pages.
+ """
+ # Add the local Kolibri source directory to the path
+ sys.path = [os.path.join(os.path.dirname(__file__), "../src")] + sys.path
+
+ import kolibri
+ from kolibri.main import initialize
+ from django.core.management import call_command
+
+ initialize(skip_update=True)
+
+ call_command(
+ "loadingpage",
+ "--output-dir",
+ output_dir,
+ "--version-text",
+ kolibri.__version__,
+ )
+
+
+def create_resource_files(output_dir):
+ """
+ Read each language directory and create resource files in the corresponding Android values folder.
+ """
+ for lang_dir in os.listdir(output_dir):
+ if lang_dir == DEFAULT_LANGUAGE:
+ dir_name = "values"
+ else:
+ if lang_dir in locale_code_map:
+ locale_dir = locale_code_map[lang_dir]
+ else:
+ parts = lang_dir.split("-")
+ if len(parts) == 1:
+ locale_dir = lang_dir
+ elif len(parts) == 2:
+ locale_dir = f"{parts[0]}-r{parts[1].upper()}"
+ else:
+ raise ValueError(f"Invalid language code: {lang_dir}")
+ dir_name = f"values-{locale_dir}"
+
+ values_dir = os.path.join(
+ os.path.dirname(__file__),
+ "../python-for-android/dists/kolibri/src/main/res",
+ dir_name,
+ )
+
+ os.makedirs(values_dir, exist_ok=True)
+
+ with open(os.path.join(output_dir, lang_dir, "loading.html"), "r") as f:
+ html_content = f.read().replace("'", "\\'").replace('"', '\\"')
+
+ xml_content = XML_TEMPLATE.format(html_content)
+
+ with open(os.path.join(values_dir, "html_content.xml"), "w") as f:
+ f.write(xml_content)
+
+
+def main():
+ """
+ Run the script to generate the loading pages and create the Android resource files.
+ """
+ with tempfile.TemporaryDirectory() as temp_dir:
+ generate_loading_pages(temp_dir)
+ create_resource_files(temp_dir)
+
+
+if __name__ == "__main__":
+ # Actually run the script
+ main()