diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 23e1f7776..afb30fd94 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -12,7 +12,9 @@ before_script:
test:
script:
- - ./app/tools/check-string-format.py
+ - ./tools/check-format-strings.py
+ - ./tools/remove-unused-and-blank-translations.py
+ - git diff | grep diff && false # there should be no changes
- ./gradlew assemble -PdisablePreDex
# always report on lint errors to the build log
- sed -i -e 's,textReport .*,textReport true,' app/build.gradle
diff --git a/app/build.gradle b/app/build.gradle
index 4207db0ea..8d5a70fee 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -245,13 +245,7 @@ android {
xmlReport false
textReport false
- // Our translations are crowd-sourced
- disable 'MissingTranslation'
-
- // to make CI fail on errors until this is fixed https://github.com/rtyley/spongycastle/issues/7
- warning 'InvalidPackage', 'ImpliedQuantity'
-
- error 'AppCompatMethod', 'NestedScrolling', 'StringFormatCount', 'UnsafeProtectedBroadcastReceiver'
+ lintConfig file("lint.xml")
}
packagingOptions {
diff --git a/app/lint.xml b/app/lint.xml
new file mode 100644
index 000000000..52da393fb
--- /dev/null
+++ b/app/lint.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusService.java b/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusService.java
index 76e2eb2a4..e6b821099 100644
--- a/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusService.java
+++ b/app/src/main/java/org/fdroid/fdroid/AppUpdateStatusService.java
@@ -44,11 +44,22 @@ public class AppUpdateStatusService extends IntentService {
@Override
protected void onHandleIntent(@Nullable Intent intent) {
Utils.debugLog(TAG, "Scanning apk cache to see if we need to prompt the user to install any apks.");
- List apksReadyToInstall = new ArrayList<>();
File cacheDir = ApkCache.getApkCacheDir(this);
- for (String repoDirName : cacheDir.list()) {
+ if (cacheDir == null) {
+ return;
+ }
+ String[] cacheDirList = cacheDir.list();
+ if (cacheDirList == null) {
+ return;
+ }
+ List apksReadyToInstall = new ArrayList<>();
+ for (String repoDirName : cacheDirList) {
File repoDir = new File(cacheDir, repoDirName);
- for (String apkFileName : repoDir.list()) {
+ String[] apks = repoDir.list();
+ if (apks == null) {
+ continue;
+ }
+ for (String apkFileName : apks) {
Apk apk = processDownloadedApk(new File(repoDir, apkFileName));
if (apk != null) {
Log.i(TAG, "Found downloaded apk " + apk.packageName + ". Notifying user that it should be installed.");
diff --git a/app/src/main/java/org/fdroid/fdroid/Languages.java b/app/src/main/java/org/fdroid/fdroid/Languages.java
index f7c47b368..30279c7ea 100644
--- a/app/src/main/java/org/fdroid/fdroid/Languages.java
+++ b/app/src/main/java/org/fdroid/fdroid/Languages.java
@@ -73,6 +73,9 @@ public final class Languages {
}
}
+ // remove the current system language from the menu
+ tmpMap.remove(currentLocale.getLanguage());
+
/* SYSTEM_DEFAULT is a fake one for displaying in a chooser menu. */
tmpMap.put(USE_SYSTEM_DEFAULT, activity.getString(resId));
nameMap = Collections.unmodifiableMap(tmpMap);
@@ -116,13 +119,21 @@ public final class Languages {
}
@TargetApi(17)
+ /**
+ * Handles setting the language if it is different than the current language,
+ * or different than the current system-wide locale. The preference is cleared
+ * if the language matches the system-wide locale or "System Default" is chosen.
+ */
public static void setLanguage(final ContextWrapper contextWrapper, String language, boolean refresh) {
if (Build.VERSION.SDK_INT >= 24) {
Utils.debugLog(TAG, "Languages.setLanguage() ignored on >= android-24");
Preferences.get().clearLanguage();
return;
}
- if (locale != null && TextUtils.equals(locale.getLanguage(), language) && (!refresh)) {
+ if (TextUtils.equals(language, DEFAULT_LOCALE.getLanguage())) {
+ Preferences.get().clearLanguage();
+ locale = DEFAULT_LOCALE;
+ } else if (locale != null && TextUtils.equals(locale.getLanguage(), language) && (!refresh)) {
return; // already configured
} else if (language == null || language.equals(USE_SYSTEM_DEFAULT)) {
Preferences.get().clearLanguage();
diff --git a/app/src/main/java/org/fdroid/fdroid/views/RepoDetailsActivity.java b/app/src/main/java/org/fdroid/fdroid/views/RepoDetailsActivity.java
index 4a58aeac2..736655d2e 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/RepoDetailsActivity.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/RepoDetailsActivity.java
@@ -27,7 +27,6 @@ import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
-
import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.NfcHelper;
import org.fdroid.fdroid.NfcNotEnabledActivity;
@@ -39,6 +38,8 @@ import org.fdroid.fdroid.data.Repo;
import org.fdroid.fdroid.data.RepoProvider;
import org.fdroid.fdroid.data.Schema.RepoTable;
+import java.util.Locale;
+
public class RepoDetailsActivity extends ActionBarActivity {
private static final String TAG = "RepoDetailsActivity";
@@ -323,7 +324,7 @@ public class RepoDetailsActivity extends ActionBarActivity {
name.setText(repo.name);
int appCount = RepoProvider.Helper.countAppsForRepo(this, repoId);
- numApps.setText(Integer.toString(appCount));
+ numApps.setText(String.format(Locale.getDefault(), "%d", appCount));
setupDescription(repoView, repo);
setupRepoFingerprint(repoView, repo);
diff --git a/app/src/main/java/org/fdroid/fdroid/views/updates/items/AppNotification.java b/app/src/main/java/org/fdroid/fdroid/views/updates/items/AppNotification.java
index dadf209e5..6ae216250 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/updates/items/AppNotification.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/updates/items/AppNotification.java
@@ -49,7 +49,7 @@ public class AppNotification extends AppUpdateData {
}
public void bindApp(AppNotification app) {
- ((TextView) itemView).setText("Notification for app");
+ ((TextView) itemView).setText("");
}
}
diff --git a/app/src/main/java/org/fdroid/fdroid/views/updates/items/DonationPrompt.java b/app/src/main/java/org/fdroid/fdroid/views/updates/items/DonationPrompt.java
index 73e306b5f..697860703 100644
--- a/app/src/main/java/org/fdroid/fdroid/views/updates/items/DonationPrompt.java
+++ b/app/src/main/java/org/fdroid/fdroid/views/updates/items/DonationPrompt.java
@@ -47,7 +47,7 @@ public class DonationPrompt extends AppUpdateData {
}
public void bindApp(DonationPrompt app) {
- ((TextView) itemView).setText("Donation prompt for app");
+ ((TextView) itemView).setText("");
}
}
diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml
index 297bf25c0..228d1455e 100644
--- a/app/src/main/res/values-be/strings.xml
+++ b/app/src/main/res/values-be/strings.xml
@@ -466,8 +466,7 @@
- Убачыць %d праграму
- Убачыць усе %d праграмы
- Убачыць усе %d праграм
-
-
+
Версія %1$s (рэкамендуецца)
Новая
@@ -486,8 +485,7 @@
- Паказаць %1$s праграму ў катэгорыі %2$s
- Паказаць %1$s праграмы ў катэгорыі %2$s
- Паказаць %1$s праграм ў катэгорыі %2$s
-
-
+
Абнавіць
Абнавіць %1$s
@@ -497,8 +495,7 @@
- Выпушчана %1$d дзень таму
- Выпушчана %1$d дня таму
- Выпушчана %1$d дзён таму
-
-
+
Спампаваць
Спампаваць усе абнаўленні
@@ -510,8 +507,7 @@
- Спампаваць абнаўленне для %1$d праграмы.
- Спампаваць абнаўленні для %1$d праграм.
- Спампаваць абнаўленні для %1$d праграм.
-
-
+
Навае ў версіі %s
@@ -520,8 +516,7 @@
- Абноўлена %1$s дзень таму
- Абноўлена %1$s дні таму
- Абноўлена %1$s дзён таму
-
-
+
Гэтая праграма мае функцыі, што могуць вам не спадабацца.
%1$s паспяхова ўсталявана
Няма інтэрнэту? Пампуйце праграмы ад людзей
diff --git a/app/src/main/res/values-kn/strings.xml b/app/src/main/res/values-kn/strings.xml
index ea8e0a014..cb719008f 100644
--- a/app/src/main/res/values-kn/strings.xml
+++ b/app/src/main/res/values-kn/strings.xml
@@ -1,5 +1,5 @@
-ಎಫ್-ಡ್ರಾಯ್ಡ್
+ಎಫ್-ಡ್ರಾಯ್ಡ್
ಆವೃತ್ತಿ
ಅನುಸ್ಥಾಪಿಸು
@@ -31,10 +31,10 @@
ನನ್ನ ಹತ್ತಿರವಿರುವ ಜನರನ್ನು ಹುಡುಕು
ಅನುಸ್ಥಾಪಿಸಲಾಗುತ್ತಿದೆ…
ಅನುಸ್ಥಾಪಿಸು
- ಸಮಯ
- ಸುರಕ್ಷತೆ
- ಕ್ರೀಡೆ & ಆರೋಗ್ಯ
- ಆಟಗಳು
+ ಸಮಯ
+ ಸುರಕ್ಷತೆ
+ ಕ್ರೀಡೆ & ಆರೋಗ್ಯ
+ ಆಟಗಳು
ವೈ-ಫೈ
ಭಾಷೆ
ಹೆಸರು
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 2e09d63e2..c34768201 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -449,8 +449,7 @@
- Zobacz %d aplikację
- Zobacz wszystkie %d aplikacje
- Zobacz wszystkich %d aplikacji
-
-
+
Wersja %1$s (zalecana)
Nowa
@@ -470,8 +469,7 @@
- Pokaż %1$d aplikację w kategorii %2$s
- Pokaż wszystkie %1$s aplikacje w kategorii %2$s
- Pokaż wszystkich %1$s aplikacji w kategorii %2$s
-
-
+
Aktualizuj
Aktualizuj %1$s
@@ -481,8 +479,7 @@
- Wydano %1$d dzień temu
- Wydano %1$d dni temu
- Wydano %1$d dni temu
-
-
+
Pobierz
Pobierz wszystkie aktualizacje
@@ -494,8 +491,7 @@
- Pobierz aktualizację dla %1$d aplikacji.
- Pobierz aktualizacje dla %1$d aplikacji.
- Pobierz aktualizacje dla %1$d aplikacji.
-
-
+
Nowe w wersji %s
@@ -506,8 +502,7 @@
- Uaktualniono %1$s dzień temu
- Uaktualniono %1$s dni temu
- Uaktualniono %1$s dni temu
-
-
+
%1$s pomyślnie zainstalowano
Brak internetu? Pobierz aplikacje od ludzi w
pobliżu!
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 5f9818a36..decdb967c 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -454,8 +454,7 @@
- Опубликовано %1$d день назад
- Опубликовано %1$d дня назад
- Опубликовано %1$d дней назад
-
-
+
Нет категорий для показа
@@ -463,8 +462,7 @@
- Посмотреть %d приложение
- Посмотреть %d приложения
- Посмотреть %d приложений
-
-
+
Нет интернета? Скачивайте приложения у людей рядом с вами!
Готово к установке
@@ -483,8 +481,7 @@
- Обновлено %1$s день назад
- Обновлено %1$s дня назад
- Обновлено %1$s дней назад
-
-
+
%1$s создано %2$s. Купи им чашечку кофе!
Версия %1$s (Рекомендуемая)
@@ -494,8 +491,7 @@
- Скачать обновления для %1$d приложения.
- Скачать обновления для %1$d приложений.
- Скачать обновления для %1$d приложений.
-
-
+
Обновить %1$s
Установить %1$s
@@ -521,8 +517,7 @@
- Посмотреть %1$d приложение в категории %2$s
- Посмотреть %1$d приложения в категории %2$s
- Посмотреть %1$d приложений в категории %2$s
-
-
+
Нет недавних приложений
Обоим участникам нужен %1$s чтобы передавать приложения.
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 7e1654a35..5a6ceb3d9 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -508,8 +508,7 @@
- Завантажити оновлення для %1$d додатку.
- Завантажити оновлення для %1$d додатка.
- Завантажити оновлення для %1$d додатків.
-
-
+
Нове у версії %s
diff --git a/app/tools/remove-unused-trans.py b/app/tools/remove-unused-trans.py
deleted file mode 100755
index 7863c2774..000000000
--- a/app/tools/remove-unused-trans.py
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env python3
-
-# Remove extra translations
-
-import glob
-import os
-import re
-from xml.etree import ElementTree
-
-strings = set()
-
-for e in ElementTree.parse(os.path.join('src', 'main', 'res', 'values', 'strings.xml')).getroot().findall('.//string'):
- name = e.attrib['name']
- strings.add(name)
-
-for d in glob.glob(os.path.join('src', 'main', 'res', 'values-*')):
-
- str_path = os.path.join(d, 'strings.xml')
- if os.path.exists(str_path):
- header = ''
- with open(str_path, 'r') as f:
- header = f.readline()
- tree = ElementTree.parse(str_path)
- root = tree.getroot()
-
- elems = root.findall('.//string')
- for e in elems:
- name = e.attrib['name']
- if name not in strings:
- root.remove(e)
- if not e.text:
- root.remove(e)
-
- result = re.sub(r' />', r'/>', ElementTree.tostring(root, encoding='utf-8').decode('utf-8'))
-
- with open(str_path, 'w+') as f:
- f.write(header)
- f.write(result)
- f.write('\n')
diff --git a/app/tools/check-string-format.py b/tools/check-format-strings.py
similarity index 90%
rename from app/tools/check-string-format.py
rename to tools/check-format-strings.py
index 00395e118..feb9af199 100755
--- a/app/tools/check-string-format.py
+++ b/tools/check-format-strings.py
@@ -13,11 +13,11 @@ formatRe = re.compile(r'(%%|%[^%](\$.)?)')
validFormatRe = re.compile(r'^(%%|%[sd]|%[0-9]\$[sd])$')
oddQuotingRe = re.compile(r'^"\s*(.+?)\s*"$')
-projectdir = os.path.join(os.path.dirname(__file__), '..')
+resdir = os.path.join(os.path.dirname(__file__), '..', 'app', 'src', 'main', 'res')
count = 0
-for d in sorted(glob.glob(os.path.join(projectdir, 'src', 'main', 'res', 'values-*'))):
+for d in sorted(glob.glob(os.path.join(resdir, 'values-*'))):
str_path = os.path.join(d, 'strings.xml')
if not os.path.exists(str_path):
diff --git a/tools/pull-trans.sh b/tools/pull-trans.sh
deleted file mode 100755
index c1144081c..000000000
--- a/tools/pull-trans.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-
-# This script pulls translations from weblate.
-#
-# It squashes all the changes into a single commit. This removes authorship
-# from the changes, which is given to the Translatebot, so to keep the names
-# they are grabbed from git log and added to the commit message.
-#
-# Note that this will apply changes and commit them! Make sure to not have
-# uncommited changes when running this script.
-
-REMOTE="weblate"
-REMOTE_URL="git://git.weblate.org/f-droid.git"
-REMOTE_BRANCH="master"
-
-AUTHOR="F-Droid Translatebot "
-
-if ! git ls-remote --exit-code $REMOTE >/dev/null 2>/dev/null; then
- echo "Remote doesn't exist! Try the following:"
- echo " git remote add $REMOTE $REMOTE_URL"
- echo " git fetch $REMOTE"
- exit 1
-fi
-
-ref="${REMOTE}/${REMOTE_BRANCH}"
-diff="HEAD...$ref -- */values-*/strings.xml"
-
-authors=$(git log --format="%s %an" $diff | \
- sed 's/.* using Weblate (\(.*\)) \(.*\)/\2||\1/' | sort -f -u | column -s '||' -t)
-
-git diff $diff | git apply
-
-git add */values-*/strings.xml
-
-git commit --author "$AUTHOR" -m "Pull translation updates from Weblate
-
-Translators:
-
-$authors"
diff --git a/tools/remove-unused-and-blank-translations.py b/tools/remove-unused-and-blank-translations.py
new file mode 100755
index 000000000..31f75679d
--- /dev/null
+++ b/tools/remove-unused-and-blank-translations.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+
+# This script removes strings from the translated files that are not useful:
+# * translations for strings that are no longer used
+# * empty translated strings, English is better than no text at all
+
+import glob
+import os
+import re
+from xml.etree import ElementTree
+
+resdir = os.path.join(os.path.dirname(__file__), '..', 'app', 'src', 'main', 'res')
+sourcepath = os.path.join(resdir, 'values', 'strings.xml')
+
+strings = set()
+for e in ElementTree.parse(sourcepath).getroot().findall('.//string'):
+ name = e.attrib['name']
+ strings.add(name)
+
+for d in sorted(glob.glob(os.path.join(resdir, 'values-*'))):
+
+ str_path = os.path.join(d, 'strings.xml')
+ if not os.path.exists(str_path):
+ continue
+
+ header = ''
+ with open(str_path, 'r') as f:
+ header = f.readline()
+
+ # handling XML namespaces in Python is painful, just remove them, they
+ # should not be in the translation files anyway
+ with open(str_path, 'rb') as fp:
+ contents = fp.read()
+ contents = contents.replace(b' tools:ignore="UnusedResources"', b'') \
+ .replace(b' xmlns:tools="http://schemas.android.com/tools"', b'')
+ root = ElementTree.fromstring(contents)
+
+ for e in root.findall('.//string'):
+ name = e.attrib['name']
+ if name not in strings:
+ root.remove(e)
+ if not e.text:
+ root.remove(e)
+
+ for e in root.findall('.//plurals'):
+ for item in e.findall('item'):
+ if not item.text:
+ e.remove(item)
+
+ result = re.sub(r' />', r'/>', ElementTree.tostring(root, encoding='utf-8').decode('utf-8'))
+
+ with open(str_path, 'w+') as f:
+ f.write(header)
+ f.write(result)
+ f.write('\n')
diff --git a/tools/trim-incomplete-translations-for-release.py b/tools/trim-incomplete-translations-for-release.py
index 75b6fd6ea..a56f173a2 100755
--- a/tools/trim-incomplete-translations-for-release.py
+++ b/tools/trim-incomplete-translations-for-release.py
@@ -1,9 +1,15 @@
#!/usr/bin/python3
+#
+# WARNING! THIS DELETES TRANSLATIONS!
+#
+# The incomplete translations should be kept by rebasing the weblate
+# remote on top of this commit, once its complete.
import csv
import git
import os
import requests
+import sys
projectbasedir = os.path.dirname(os.path.dirname(__file__))
@@ -11,7 +17,7 @@ print(projectbasedir)
repo = git.Repo(projectbasedir)
-msg = 'removing all translations less than 75% complete\n\n'
+msg = 'removing all translations less than 70% complete\n\n'
url = 'https://hosted.weblate.org/exports/stats/f-droid/f-droid/?format=csv'
r = requests.get(url)
@@ -19,7 +25,7 @@ stats = csv.reader(r.iter_lines(decode_unicode=True), delimiter=',')
next(stats) # skip CSV header
for row in stats:
if len(row) > 4:
- if float(row[4]) > 75.0:
+ if float(row[4]) > 70.0:
continue
locale = row[1]
if '_' in locale:
@@ -33,10 +39,22 @@ for row in stats:
percent = str(int(float(row[4]))) + '%'
print('Removing incomplete file: (' + percent + ')\t',
translation_file)
- os.remove(os.path.join(projectbasedir, translation_file))
- repo.index.remove([translation_file, ])
+ delfile = os.path.join(projectbasedir, translation_file)
+ if os.path.exists(delfile):
+ os.remove(delfile)
+ repo.index.remove([translation_file, ])
if len(percent) == 2:
msg += ' '
msg += percent + ' ' + row[1] + ' ' + row[0] + '\n'
+found = False
+for remote in repo.remotes:
+ if remote.name == 'weblate':
+ remote.fetch()
+ found = True
+
+if not found:
+ print('ERROR: there must be a weblate remote to preserve incomplete translations!')
+ sys.exit(1)
+
repo.index.commit(msg)