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)