From e35335d59cb79955b107d8bdc8f99aed48390ca8 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 5 Feb 2021 16:36:47 +0100 Subject: [PATCH] totally overhaul choosing locales from app metadata based on LocaleList This makes the selection logic heed the list of preferred locales from the user Settings. closes #987 closes #1186 refs #1440 #1882 #1730 !886 --- .../java/org/fdroid/fdroid/FDroidApp.java | 2 + .../main/java/org/fdroid/fdroid/data/App.java | 289 +++++++++--------- .../java/org/fdroid/fdroid/data/Schema.java | 7 + .../fdroid/fdroid/data/AppProviderTest.java | 5 +- .../fdroid/data/LocaleSelectionTest.java | 230 ++++++++------ .../fdroid/updater/IndexV1UpdaterTest.java | 1 + app/src/test/resources/localized.json | 285 +++++++++++++++++ 7 files changed, 585 insertions(+), 234 deletions(-) create mode 100644 app/src/test/resources/localized.json diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java index b533b27f9..be010ef0c 100644 --- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java +++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java @@ -67,6 +67,7 @@ import org.apache.commons.net.util.SubnetUtils; import org.fdroid.fdroid.Preferences.ChangeListener; import org.fdroid.fdroid.Preferences.Theme; import org.fdroid.fdroid.compat.PRNGFixes; +import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.InstalledAppProviderService; import org.fdroid.fdroid.data.Repo; @@ -330,6 +331,7 @@ public class FDroidApp extends Application { public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); Languages.setLanguage(this); + App.systemLocaleList = null; // update the descriptions based on the new language preferences SharedPreferences atStartTime = getAtStartTimeSharedPreferences(); diff --git a/app/src/main/java/org/fdroid/fdroid/data/App.java b/app/src/main/java/org/fdroid/fdroid/data/App.java index af7bb638e..316177284 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/App.java +++ b/app/src/main/java/org/fdroid/fdroid/data/App.java @@ -10,7 +10,6 @@ import android.content.res.AssetManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.database.Cursor; -import android.os.Build; import android.os.Environment; import android.os.LocaleList; import android.os.Parcel; @@ -19,6 +18,8 @@ import android.text.TextUtils; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.os.ConfigurationCompat; +import androidx.core.os.LocaleListCompat; import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -41,8 +42,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.Enumeration; +import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -75,6 +76,14 @@ public class App extends ValueObject implements Comparable, Parcelable { @JsonIgnore private static final String TAG = "App"; + /** + * {@link LocaleListCompat} for finding the right app description material. + * It is set globally static to a) cache this value, since there are thousands + * of {@link App} entries, and b) make it easy to test {@link #setLocalized(Map)} )} + */ + @JsonIgnore + public static LocaleListCompat systemLocaleList; + // these properties are not from the index metadata, but represent the state on the device /** * True if compatible with the device (i.e. if at least one apk is) @@ -98,8 +107,12 @@ public class App extends ValueObject implements Comparable, Parcelable { public String preferredSigner; @JsonIgnore public boolean isApk; + + /** + * Has this {@code App} been localized into one of the user's current locales. + */ @JsonIgnore - boolean isLocalized = false; + boolean isLocalized; /** * This is primarily for the purpose of saving app metadata when parsing an index.xml file. @@ -484,110 +497,25 @@ public class App extends ValueObject implements Comparable, Parcelable { * {@code localized} block is included in the index. Also, null strings in * the {@code localized} block should not overwrite Name/Summary/Description * strings with empty/null if they were set directly by Jackson. - *

- * Choosing the locale to use follows two sets of rules, one for Android versions - * older than {@code android-24} and the other for {@code android-24} or newer. - * The system-wide language preference list was added in {@code android-24}. - *

    - *
  • {@code >= android-24}
      + *
        *
      1. the country variant {@code de-AT} from the user locale list *
      2. only the language {@code de} from the above locale + *
      3. next locale in the user's preference list ({@code >= android-24}) *
      4. {@code en-US} since its the most common English for software *
      5. the first available {@code en} locale - *
      - *
    1. {@code < android-24}
        - *
      1. the country variant from the user locale: {@code de-AT} - *
      2. only the language from the above locale: {@code de} - *
      3. all available locales with the same language: {@code de-BE} - *
      4. {@code en-US} since its the most common English for software - *
      5. all available {@code en} locales - *
    2. - *
- * On {@code >= android-24}, it is by design that this does not fallback to other - * country-specific locales, e.g. {@code fr-CH} does not fall back on {@code fr-FR}. - * If someone wants to fallback to {@code fr-FR}, they can add it to the system - * language list. There are many cases where it is inappropriate to fallback to a - * different country-specific locale, for example {@code de-DE --> de-CH} or - * {@code zh-CN --> zh-TW}. + * *

- * On {@code < android-24}, the user can only set a single - * locale with a country as an option, so here it makes sense to try to fallback - * on other country-specific locales, rather than English. + * The system-wide language preference list was added in {@code android-24}. + * + * @see Android language and locale resolution overview */ @JsonProperty("localized") void setLocalized(Map> localized) { // NOPMD - Locale defaultLocale = Locale.getDefault(); - String languageTag = defaultLocale.getLanguage(); - String countryTag = defaultLocale.getCountry(); - String localeTag; - if (TextUtils.isEmpty(countryTag)) { - localeTag = languageTag; - } else { - localeTag = languageTag + "-" + countryTag; + if (systemLocaleList == null) { + systemLocaleList = ConfigurationCompat.getLocales(Resources.getSystem().getConfiguration()); } - - Set availableLocales = localized.keySet(); - Set localesToUse = new LinkedHashSet<>(); - if (availableLocales.contains(localeTag)) { - localesToUse.add(localeTag); - } - if (availableLocales.contains(languageTag)) { - localesToUse.add(languageTag); - } - if (localesToUse.isEmpty()) { - // In case of non-standard region like [en-SE] - for (String availableLocale : availableLocales) { - String availableLanguage = availableLocale.split("-")[0]; - if (languageTag.equals(availableLanguage)) { - localesToUse.add(availableLocale); - } - } - } - if (Build.VERSION.SDK_INT >= 24) { - LocaleList localeList = Resources.getSystem().getConfiguration().getLocales(); - String[] sortedLocaleList = localeList.toLanguageTags().split(","); - Arrays.sort(sortedLocaleList, new java.util.Comparator() { - @Override - public int compare(String s1, String s2) { - return s1.length() - s2.length(); - } - }); - for (String toUse : sortedLocaleList) { - localesToUse.add(toUse); - for (String l : availableLocales) { - if (l.equals(toUse.split("-")[0])) { - localesToUse.add(l); - break; - } - } - } - } else { - for (String l : availableLocales) { - if (l.startsWith(languageTag)) { - localesToUse.add(l); - } - } - } - if (availableLocales.contains("en-US")) { - localesToUse.add("en-US"); - } - for (String l : availableLocales) { - if (l.startsWith("en")) { - localesToUse.add(l); - break; - } - } - - for (String l : localesToUse) { - if (l.startsWith(languageTag)) { - isLocalized = true; - break; - } - } - if (localesToUse.size() > 1) { - isLocalized = true; - } - + Set localesToUse = localized.keySet(); + setIsLocalized(localesToUse); String value = getLocalizedEntry(localized, localesToUse, "whatsNew"); if (!TextUtils.isEmpty(value)) { whatsNew = value; @@ -625,73 +553,148 @@ public class App extends ValueObject implements Comparable, Parcelable { } /** - * Returns the right localized version of this entry, based on an immitation of - * the logic that Android/Java uses. On Android >= 24, this can get the - * "Language Priority List", but it doesn't always seem to be properly sorted. - * So this method has to kind of fake it by using {@link Locale#getDefault()} - * as the first entry, then sorting the rest based on length (e.g. {@code de-AT} - * before {@code de}). + * Sets the boolean flag {@link #isLocalized} if this app entry has an localized + * entry in one of the user's current locales. * - * @see LocaleList - * @see Locale#getDefault() - * @see java.util.Locale.LanguageRange + * @see org.fdroid.fdroid.views.main.WhatsNewViewBinder#onCreateLoader(int, android.os.Bundle) */ - private String getLocalizedEntry(Map> localized, - Set locales, String key) { - try { - for (String locale : locales) { - if (localized.containsKey(locale)) { - String value = (String) localized.get(locale).get(key); - if (value != null) { - return value; - } + private void setIsLocalized(Set supportedLocales) { + isLocalized = false; + for (int i = 0; i < systemLocaleList.size(); i++) { + String language = systemLocaleList.get(i).getLanguage(); + for (String supportedLocale : supportedLocales) { + if (language.equals(supportedLocale.split("-")[0])) { + isLocalized = true; + return; } } - } catch (ClassCastException e) { - Utils.debugLog(TAG, e.getMessage()); + } + } + + /** + * Returns the right localized version of this entry, based on an imitation of + * the logic that Android uses. + * + * @see LocaleList + */ + private String getLocalizedEntry(Map> localized, + Set locales, @NonNull String key) { + Map localizedLocaleMap = getLocalizedLocaleMap(localized, locales, key); + if (localizedLocaleMap != null && !localizedLocaleMap.isEmpty()) { + for (Object entry : localizedLocaleMap.values()) { + return (String) entry; // NOPMD + } } return null; } private String getLocalizedGraphicsEntry(Map> localized, Set locales, String key) { - try { - for (String locale : locales) { - Map entry = localized.get(locale); - if (entry != null) { - Object value = entry.get(key); - if (value != null && value.toString().length() > 0) { - return locale + "/" + value; - } - } + Map localizedLocaleMap = getLocalizedLocaleMap(localized, locales, key); + if (localizedLocaleMap != null && !localizedLocaleMap.isEmpty()) { + for (String locale : localizedLocaleMap.keySet()) { + return locale + "/" + localizedLocaleMap.get(locale); // NOPMD } - } catch (ClassCastException e) { - Utils.debugLog(TAG, e.getMessage()); } return null; } private String[] getLocalizedListEntry(Map> localized, Set locales, String key) { - try { - for (String locale : locales) { - if (localized.containsKey(locale)) { - ArrayList entry = (ArrayList) localized.get(locale).get(key); - if (entry != null && entry.size() > 0) { - String[] result = new String[entry.size()]; - int i = 0; - for (String e : entry) { - result[i] = locale + "/" + key + "/" + e; - i++; + Map localizedLocaleMap = getLocalizedLocaleMap(localized, locales, key); + if (localizedLocaleMap != null && !localizedLocaleMap.isEmpty()) { + for (String locale : localizedLocaleMap.keySet()) { + ArrayList entry = (ArrayList) localizedLocaleMap.get(locale); + if (entry != null && entry.size() > 0) { + String[] result = new String[entry.size()]; + int i = 0; + for (String e : entry) { + result[i] = locale + "/" + key + "/" + e; + i++; + } + return result; + } + } + } + return new String[0]; + } + + /** + * Return one matching entry from the {@code localized} block in the app entry + * in the index JSON. + */ + private Map getLocalizedLocaleMap(Map> localized, + Set locales, String key) { + String[] localesToUse = getLocalesForKey(localized, locales, key); + if (localesToUse.length > 0) { + Locale firstMatch = systemLocaleList.getFirstMatch(localesToUse); + if (firstMatch != null) { + for (String languageTag : new String[]{firstMatch.toLanguageTag(), null}) { + if (languageTag == null) { + languageTag = getFallbackLanguageTag(firstMatch, localesToUse); // NOPMD + } + Map localeEntry = localized.get(languageTag); + if (localeEntry != null && localeEntry.containsKey(key)) { + Object value = localeEntry.get(key); + if (value != null) { + Map localizedLocaleMap = new HashMap<>(); + localizedLocaleMap.put(languageTag, value); + return localizedLocaleMap; } - return result; } } } - } catch (ClassCastException e) { - Utils.debugLog(TAG, e.getMessage()); } - return new String[0]; + return null; + } + + /** + * Get all locales that have an entry for {@code key}. + */ + private String[] getLocalesForKey(Map> localized, + Set locales, String key) { + Set localesToUse = new HashSet<>(); + for (String locale : locales) { + Map localeEntry = localized.get(locale); + if (localeEntry != null && localeEntry.get(key) != null) { + localesToUse.add(locale); + } + } + return localesToUse.toArray(new String[0]); + } + + /** + * Look for the first language-country match for languages with multiple scripts. + * Then look for a language-only match, for when there is no exact + * {@link Locale} match. Then try a locale with the same language, but + * different country. If there are still no matches, return the {@code en-US} + * entry. If all else fails, try to return the first existing English locale. + */ + private String getFallbackLanguageTag(Locale firstMatch, String[] localesToUse) { + final String firstMatchLanguageCountry = firstMatch.getLanguage() + "-" + firstMatch.getCountry(); + for (String languageTag : localesToUse) { + if (languageTag.equals(firstMatchLanguageCountry)) { + return languageTag; + } + } + final String firstMatchLanguage = firstMatch.getLanguage(); + String englishLastResort = null; + for (String languageTag : localesToUse) { + if (languageTag.equals(firstMatchLanguage)) { + return languageTag; + } else if ("en-US".equals(languageTag)) { + englishLastResort = languageTag; + } + } + for (String languageTag : localesToUse) { + String languageToUse = languageTag.split("-")[0]; + if (firstMatchLanguage.equals(languageToUse)) { + return languageTag; + } else if (englishLastResort == null && "en".equals(languageToUse)) { + englishLastResort = languageTag; + } + } + return englishLastResort; } /** diff --git a/app/src/main/java/org/fdroid/fdroid/data/Schema.java b/app/src/main/java/org/fdroid/fdroid/data/Schema.java index e3a6d3e0b..9deef9dd0 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Schema.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Schema.java @@ -209,6 +209,13 @@ public interface Schema { String TV_SCREENSHOTS = "tvScreenshots"; String WEAR_SCREENSHOTS = "wearScreenshots"; String IS_APK = "isApk"; + + /** + * Has this {@code App} been localized into one of the user's current locales. + * + * @see App#setIsLocalized(java.util.Set) + * @see org.fdroid.fdroid.views.main.WhatsNewViewBinder#onCreateLoader(int, android.os.Bundle) + */ String IS_LOCALIZED = "isLocalized"; interface AutoInstallApk { diff --git a/app/src/test/java/org/fdroid/fdroid/data/AppProviderTest.java b/app/src/test/java/org/fdroid/fdroid/data/AppProviderTest.java index c35ccd1cf..92ec0a53d 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/AppProviderTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/AppProviderTest.java @@ -6,6 +6,7 @@ import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.net.Uri; +import androidx.core.os.LocaleListCompat; import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols; @@ -303,7 +304,7 @@ public class AppProviderTest extends FDroidProviderTest { localized.put("es", es); localized.put("fr", fr); - Locale.setDefault(new Locale("nl", "NL")); + App.systemLocaleList = LocaleListCompat.forLanguageTags("nl-NL"); app.setLocalized(localized); assertFalse(app.isLocalized); @@ -324,7 +325,7 @@ public class AppProviderTest extends FDroidProviderTest { app.setLocalized(localized); assertFalse(app.isLocalized); - Locale.setDefault(new Locale("en", "US")); + App.systemLocaleList = LocaleListCompat.forLanguageTags("en-US"); app = new App(); localized.clear(); localized.put("en-US", en); diff --git a/app/src/test/java/org/fdroid/fdroid/data/LocaleSelectionTest.java b/app/src/test/java/org/fdroid/fdroid/data/LocaleSelectionTest.java index 184d93dbc..9aed5e20a 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/LocaleSelectionTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/LocaleSelectionTest.java @@ -1,23 +1,27 @@ package org.fdroid.fdroid.data; -import android.content.res.Configuration; import android.os.Build; -import android.os.LocaleList; +import androidx.core.os.LocaleListCompat; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.io.FileUtils; import org.fdroid.fdroid.TestUtils; +import org.junit.Assume; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; +import org.robolectric.shadows.ShadowLog; +import java.io.File; +import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) @SuppressWarnings("LocalVariableName") @@ -25,83 +29,25 @@ public class LocaleSelectionTest { private static final String KEY = "summary"; - @Test - public void correctLocaleSelectionBeforeSDK24() throws Exception { - TestUtils.setFinalStatic(Build.VERSION.class.getDeclaredField("SDK_INT"), 19); - assertTrue(Build.VERSION.SDK_INT < 24); - App app; + private static final String EN_US_NAME = "Checkey: info on local apps\n"; + private static final String EN_US_FEATURE_GRAPHIC = "en-US/featureGraphic.png"; + private static final String EN_US_PHONE_SCREENSHOT = "en-US/phoneScreenshots/First.png"; + private static final String EN_US_SEVEN_INCH_SCREENSHOT = "en-US/sevenInchScreenshots/checkey-tablet.png"; + private static final String FR_FR_NAME = "Checkey : infos applis locales"; + private static final String FR_CA_FEATURE_GRAPHIC = "fr-CA/featureGraphic.png"; + private static final String FR_FR_FEATURE_GRAPHIC = "fr-FR/featureGraphic.png"; + private static final String FR_FR_SEVEN_INCH_SCREENSHOT = "fr-FR/sevenInchScreenshots/checkey-tablet.png"; - Map> localized = new HashMap<>(); - HashMap en_US = new HashMap<>(); - en_US.put(KEY, "summary-en_US"); - HashMap de_AT = new HashMap<>(); - de_AT.put(KEY, "summary-de_AT"); - HashMap de_DE = new HashMap<>(); - de_DE.put(KEY, "summary-de_DE"); - HashMap sv = new HashMap<>(); - sv.put(KEY, "summary-sv"); - HashMap sv_FI = new HashMap<>(); - sv_FI.put(KEY, "summary-sv_FI"); - - localized.put("de-AT", de_AT); - localized.put("de-DE", de_DE); - localized.put("en-US", en_US); - localized.put("sv", sv); - localized.put("sv-FI", sv_FI); - - // Easy mode. en-US metadata with an en-US locale - Locale.setDefault(new Locale("en", "US")); - app = new App(); - app.setLocalized(localized); - assertEquals(en_US.get(KEY), app.summary); - - // Fall back to en-US locale, when we have a different en locale - Locale.setDefault(new Locale("en", "UK")); - app = new App(); - app.setLocalized(localized); - assertEquals(en_US.get(KEY), app.summary); - - // Fall back to language only - Locale.setDefault(new Locale("en", "UK")); - app = new App(); - app.setLocalized(localized); - assertEquals(en_US.get(KEY), app.summary); - - // select the correct one out of multiple language locales - Locale.setDefault(new Locale("de", "DE")); - app = new App(); - app.setLocalized(localized); - assertEquals(de_DE.get(KEY), app.summary); - - // Even when we have a non-exact matching locale, we should fall back to the same language - Locale.setDefault(new Locale("de", "CH")); - app = new App(); - app.setLocalized(localized); - assertEquals(de_AT.get(KEY), app.summary); - - // Test fallback to base lang with not exact matching locale - Locale.setDefault(new Locale("sv", "SE")); - app = new App(); - app.setLocalized(localized); - assertEquals(sv.get(KEY), app.summary); + @Before + public final void setUp() { + ShadowLog.stream = System.out; } @Test - public void correctLocaleSelectionFromSDK24() throws Exception { + public void localeSelection() throws Exception { - TestUtils.setFinalStatic(Build.VERSION.class.getDeclaredField("SDK_INT"), 29); - assertTrue(Build.VERSION.SDK_INT >= 24); - - App app = spy(new App()); - - // we mock both the getLocales call and the conversion to a language tag string. - Configuration configuration = mock(Configuration.class); - LocaleList localeList = mock(LocaleList.class); - doReturn(localeList).when(configuration).getLocales(); - - // Set both default locale as well as the locale list, because the algorithm uses both... - Locale.setDefault(new Locale("en", "US")); - when(localeList.toLanguageTags()).thenReturn("en-US,de-DE"); + App app = new App(); + App.systemLocaleList = LocaleListCompat.forLanguageTags("en-US,de-DE"); //no metadata present Map> localized = new HashMap<>(); @@ -112,10 +58,18 @@ public class LocaleSelectionTest { en_US.put(KEY, "summary-en_US"); HashMap en_GB = new HashMap<>(); en_GB.put(KEY, "summary-en_GB"); + HashMap de = new HashMap<>(); + de.put(KEY, "summary-de"); HashMap de_AT = new HashMap<>(); de_AT.put(KEY, "summary-de_AT"); HashMap de_DE = new HashMap<>(); de_DE.put(KEY, "summary-de_DE"); + HashMap es_ES = new HashMap<>(); + es_ES.put(KEY, "summary-es_ES"); + HashMap fr_FR = new HashMap<>(); + fr_FR.put(KEY, "summary-fr_FR"); + HashMap it_IT = new HashMap<>(); + it_IT.put(KEY, "summary-it_IT"); app.summary = "reset"; localized.put("de-AT", de_AT); @@ -125,8 +79,7 @@ public class LocaleSelectionTest { // just select the matching en-US locale, nothing special here assertEquals(en_US.get(KEY), app.summary); - Locale.setDefault(new Locale("en", "SE")); - when(localeList.toLanguageTags()).thenReturn("en-SE,de-DE"); + App.systemLocaleList = LocaleListCompat.forLanguageTags("en-SE,de-DE"); app.setLocalized(localized); // Fall back to another en locale before de assertEquals(en_US.get(KEY), app.summary); @@ -138,8 +91,7 @@ public class LocaleSelectionTest { localized.put("en-GB", en_GB); localized.put("en-US", en_US); - Locale.setDefault(new Locale("de", "AT")); - when(localeList.toLanguageTags()).thenReturn("de-AT,de-DE"); + App.systemLocaleList = LocaleListCompat.forLanguageTags("de-AT,de-DE"); app.setLocalized(localized); // full match against a non-default locale assertEquals(de_AT.get(KEY), app.summary); @@ -147,14 +99,13 @@ public class LocaleSelectionTest { app.summary = "reset"; localized.clear(); localized.put("de-AT", de_AT); - localized.put("de", de_DE); + localized.put("de", de); localized.put("en-GB", en_GB); localized.put("en-US", en_US); - Locale.setDefault(new Locale("de", "CH")); - when(localeList.toLanguageTags()).thenReturn("de-CH,en-US"); + App.systemLocaleList = LocaleListCompat.forLanguageTags("de-CH,en-US"); app.setLocalized(localized); - assertEquals(de_DE.get(KEY), app.summary); + assertEquals(de.get(KEY), app.summary); app.summary = "reset"; localized.clear(); @@ -162,13 +113,12 @@ public class LocaleSelectionTest { localized.put("en-US", en_US); Locale.setDefault(new Locale("en", "AU")); - when(localeList.toLanguageTags()).thenReturn("en-AU"); + App.systemLocaleList = LocaleListCompat.forLanguageTags("en-AU"); app.setLocalized(localized); assertEquals(en_US.get(KEY), app.summary); app.summary = "reset"; - Locale.setDefault(new Locale("zh", "TW", "#Hant")); - when(localeList.toLanguageTags()).thenReturn("zh-Hant-TW,zh-Hans-CN"); + App.systemLocaleList = LocaleListCompat.forLanguageTags("zh-Hant-TW,zh-Hans-CN"); localized.clear(); localized.put("en", en_GB); localized.put("en-US", en_US); @@ -197,5 +147,107 @@ public class LocaleSelectionTest { localized.put("zh-CN", zh_CN); app.setLocalized(localized); assertEquals(zh_CN.get(KEY), app.summary); + + localized.clear(); + localized.put("en-US", en_US); + localized.put("zh-CN", zh_CN); + app.setLocalized(localized); + assertEquals(zh_CN.get(KEY), app.summary); + + // https://developer.android.com/guide/topics/resources/multilingual-support#resource-resolution-examples + App.systemLocaleList = LocaleListCompat.forLanguageTags("fr-CH"); + localized.clear(); + localized.put("en-US", en_US); + localized.put("de-DE", de_DE); + localized.put("es-ES", es_ES); + localized.put("fr-FR", fr_FR); + localized.put("it-IT", it_IT); + app.setLocalized(localized); + assertEquals(fr_FR.get(KEY), app.summary); + + // https://developer.android.com/guide/topics/resources/multilingual-support#t-2d-choice + App.systemLocaleList = LocaleListCompat.forLanguageTags("fr-CH,it-CH"); + localized.clear(); + localized.put("en-US", en_US); + localized.put("de-DE", de_DE); + localized.put("es-ES", es_ES); + localized.put("it-IT", it_IT); + app.setLocalized(localized); + assertEquals(it_IT.get(KEY), app.summary); + } + + @Test + public void testSetLocalized() throws IOException { + Assume.assumeTrue(Build.VERSION.SDK_INT >= 24); + + File f = TestUtils.copyResourceToTempFile("localized.json"); + Map result = new ObjectMapper().readValue( + FileUtils.readFileToString(f, (String) null), HashMap.class); + List> apps = (List>) result.get("apps"); + Map> localized = (Map>) apps.get(0).get("localized"); + App app = new App(); + + App.systemLocaleList = LocaleListCompat.create(Locale.US); + app.setLocalized(localized); + assertEquals(EN_US_NAME, app.name); + assertEquals(EN_US_FEATURE_GRAPHIC, app.featureGraphic); + assertEquals(EN_US_PHONE_SCREENSHOT, app.phoneScreenshots[0]); + assertEquals(EN_US_SEVEN_INCH_SCREENSHOT, app.sevenInchScreenshots[0]); + assertTrue(app.isLocalized); + + // choose the language when there is an exact locale match + App.systemLocaleList = LocaleListCompat.forLanguageTags("fr-FR"); + app.setLocalized(localized); + assertEquals(FR_FR_NAME, app.name); + assertEquals(FR_FR_FEATURE_GRAPHIC, app.featureGraphic); + assertEquals(EN_US_PHONE_SCREENSHOT, app.phoneScreenshots[0]); + assertEquals(FR_FR_SEVEN_INCH_SCREENSHOT, app.sevenInchScreenshots[0]); + assertTrue(app.isLocalized); + + // choose the language from a different country when the preferred country is not available, + // while still choosing featureGraphic from exact match + App.systemLocaleList = LocaleListCompat.create(Locale.CANADA_FRENCH); + app.setLocalized(localized); + assertEquals(FR_FR_NAME, app.name); + assertEquals(FR_CA_FEATURE_GRAPHIC, app.featureGraphic); + assertEquals(EN_US_PHONE_SCREENSHOT, app.phoneScreenshots[0]); + assertEquals(FR_FR_SEVEN_INCH_SCREENSHOT, app.sevenInchScreenshots[0]); + assertTrue(app.isLocalized); + + // choose the third preferred language when first and second lack translations + App.systemLocaleList = LocaleListCompat.forLanguageTags("bo-IN,sr-RS,fr-FR"); + app.setLocalized(localized); + assertEquals(FR_FR_NAME, app.name); + assertEquals(FR_FR_FEATURE_GRAPHIC, app.featureGraphic); + assertEquals(EN_US_PHONE_SCREENSHOT, app.phoneScreenshots[0]); + assertEquals(FR_FR_SEVEN_INCH_SCREENSHOT, app.sevenInchScreenshots[0]); + assertTrue(app.isLocalized); + + // choose first language from different country, rather than 2nd full lang/country match + App.systemLocaleList = LocaleListCompat.forLanguageTags("en-GB,fr-FR"); + app.setLocalized(localized); + assertEquals(EN_US_NAME, app.name); + assertEquals(EN_US_FEATURE_GRAPHIC, app.featureGraphic); + assertEquals(EN_US_PHONE_SCREENSHOT, app.phoneScreenshots[0]); + assertEquals(EN_US_SEVEN_INCH_SCREENSHOT, app.sevenInchScreenshots[0]); + assertTrue(app.isLocalized); + + // choose en_US when no match, and mark as not localized + App.systemLocaleList = LocaleListCompat.forLanguageTags("bo-IN,sr-RS"); + app.setLocalized(localized); + assertEquals(EN_US_NAME, app.name); + assertEquals(EN_US_FEATURE_GRAPHIC, app.featureGraphic); + assertEquals(EN_US_PHONE_SCREENSHOT, app.phoneScreenshots[0]); + assertEquals(EN_US_SEVEN_INCH_SCREENSHOT, app.sevenInchScreenshots[0]); + assertFalse(app.isLocalized); + + // When English is the preferred language and the second language has no entries + App.systemLocaleList = LocaleListCompat.forLanguageTags("en-US,sr-RS"); + app.setLocalized(localized); + assertEquals(EN_US_NAME, app.name); + assertEquals(EN_US_FEATURE_GRAPHIC, app.featureGraphic); + assertEquals(EN_US_PHONE_SCREENSHOT, app.phoneScreenshots[0]); + assertEquals(EN_US_SEVEN_INCH_SCREENSHOT, app.sevenInchScreenshots[0]); + assertTrue(app.isLocalized); } } diff --git a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java index 008ae4ed2..ce90823b1 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java @@ -370,6 +370,7 @@ public class IndexV1UpdaterTest extends FDroidProviderTest { "isLocalized", "preferredSigner", "prefs", + "systemLocaleList", "TAG", }; runJsonIgnoreTest(new App(), allowedInApp, ignoredInApp); diff --git a/app/src/test/resources/localized.json b/app/src/test/resources/localized.json new file mode 100644 index 000000000..21c6952df --- /dev/null +++ b/app/src/test/resources/localized.json @@ -0,0 +1,285 @@ +{ + "repo": { + "timestamp": 1594261131000, + "version": 21, + "maxage": 14, + "name": "Guardian Project Official Releases", + "icon": "guardianproject.png", + "address": "https://guardianproject.info/fdroid/repo", + "description": "The official repository of The Guardian Project apps for use with the F-Droid client. Applications in this repository are official binaries built by the original application developers and signed by the same key as the APKs that are released in the Google Play Store. ", + "mirrors": [ + "http://bdf2wcxujkg6qqff.onion/fdroid/repo", + "https://guardianproject.info/fdroid/repo", + "https://s3.amazonaws.com/guardianproject/fdroid/repo" + ] + }, + "requests": { + "install": [], + "uninstall": [] + }, + "apps": [ + { + "authorEmail": "support@guardianproject.info", + "authorName": "Guardian Project", + "authorWebSite": "https://guardianproject.info", + "binaries": "https://guardianproject.info/releases/Checkey-%v.apk", + "bitcoin": "1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk", + "categories": [ + "Development", + "Guardian Project" + ], + "suggestedVersionName": "0.1.3", + "suggestedVersionCode": "103", + "issueTracker": "https://gitlab.com/guardianproject/checkey/issues", + "liberapayID": "33617", + "license": "GPL-3.0-or-later", + "name": "Checkey", + "sourceCode": "https://gitlab.com/guardianproject/checkey", + "translation": "https://hosted.weblate.org/projects/guardianproject/checkey/", + "webSite": "https://dev.guardianproject.info/projects/checkey", + "added": 1405123200000, + "icon": "info.guardianproject.checkey.102.png", + "packageName": "info.guardianproject.checkey", + "lastUpdated": 1425859200000, + "localized": { + "af": { + "summary": "nut om inligting oor die APKs wat op jou toestel ge\u00efnstalleer is" + }, + "ar": { + "summary": "\u0623\u062f\u0627\u0629 \u0644\u0644\u062d\u0635\u0648\u0644 \u0639\u0644\u0649 \u0645\u0639\u0644\u0648\u0645\u0627\u062a \u062d\u0648\u0644 \u0645\u0644\u0641\u0627\u062a APK \u0627\u0644\u062a\u064a \u062a\u0645 \u062a\u062b\u0628\u064a\u062a\u0647\u0627 \u0639\u0644\u0649 \u062c\u0647\u0627\u0632\u0643" + }, + "az-AZ": { + "description": "Checkey al\u0259tiniz\u0259 y\u00fckl\u0259diyiniz t\u0259tbiqetm\u0259l\u0259rinin APK-s\u0131 haqda m\u0259lumatlar\u0131 \u00fcz\u0259 \u00e7\u0131xarmaq \u00fc\u00e7\u00fcnd\u00fcr. Al\u0259tinizd\u0259ki t\u0259tbiqetm\u0259l\u0259rinin siyah\u0131s\u0131na baxmaqdan ba\u015flayaraq, bir toxunu\u015fla APK imzalar\u0131n\u0131 g\u00f6st\u0259r\u0259c\u0259k v\u0259 virustotal.com v\u0259 androidobservatory.org il\u0259 o APK-l\u0259rin profill\u0259rini izl\u0259m\u0259k imkan\u0131 ver\u0259c\u0259k. O, h\u0259m d\u0259 Trusted\u0130ntents kitabxanas\u0131 vasit\u0259sil\u0259 imzalanm\u0131\u015f sertifikatlar\u0131 ixrac etm\u0259k v\u0259 ApkSignaturePin pin fayllar yaratma\u011fa imkan ver\u0259c\u0259k.\n\u2605 S\u0130Z\u0130N D\u0130L\u0130N\u0130ZD\u018f DANI\u015eIRIQ: bu dill\u0259ri bil\u0259n dostlar \u00fc\u00e7\u00fcn \u0259l\u00e7at\u0131ml\u0131d\u0131r:\nDeutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk, portugu\u00eas (Portugal), \u0420\u0443\u0441\u0441\u043a\u0438\u0439, Sloven\u0161\u010dina, T\u00fcrk\u00e7e\n\u00d6z dilinizi tapmad\u0131n\u0131z? Biz\u0259 qo\u015ful v\u0259 t\u0259tbiqetm\u0259ni t\u0259rc\u00fcm\u0259 et:\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n***\u018ftrafl\u0131***\n\u2605 HAQQIMIZDA: Guardian Project t\u0259hl\u00fck\u0259siz mobil t\u0259tbiqetm\u0259l\u0259r v\u0259 a\u00e7\u0131q kodlar\u0131n yax\u015f\u0131 g\u0259l\u0259c\u0259k \u00fc\u00e7\u00fcn yaradan proqram\u00e7\u0131lar qrupudur\n\u2605 SAYTIMIZ: https://GuardianProject.info\n\u2605 TWITTER-d\u0259: https://twitter.com/guardianproject\n\u2605 PULSUZ PROQRAM: Checkey Pulsuz proqramd\u0131r. Siz m\u0259nb\u0259 kodumuza baxa bil\u0259r v\u0259 ya Checkey-i daha yax\u015f\u0131 etm\u0259k \u00fc\u00e7\u00fcn k\u00f6m\u0259k ed\u0259 bil\u0259rsiniz:\nhttps://gitlab.com/guardianproject/checkey\n\u2605 B\u0130Z\u018f YAZIN: \u0130st\u0259diyiniz imkan\u0131 tapa bilm\u0259diniz? Z\u0259hl\u0259t\u00f6k\u0259n x\u0259ta tapd\u0131n\u0131z? Z\u0259hm\u0259t olmasa, biz\u0259 deyin! Sizi e\u015fitm\u0259kd\u0259n \u015fad olar\u0131q. Biz\u0259 email g\u00f6nd\u0259rin: support@guardianproject.info v\u0259 ya \u00e7at ota\u011f\u0131nda bizi tap\u0131n https://guardianproject.info/contact\n", + "name": "Checkey: t\u0259tbiqetm\u0259l\u0259r haqda\n", + "summary": "v\u0259 al\u0259tiniz\u0259 y\u00fckl\u0259n\u0259n al\u0259tl\u0259rin APK m\u0259lumatlar\u0131n\u0131 \u0259ld\u0259 etm\u0259k \u00fc\u00e7\u00fcnd\u00fcr\n" + }, + "bg": { + "summary": "\u043f\u043e\u043c\u043e\u0449\u043d\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0430 \u0437\u0430 \u043e\u0441\u0438\u0433\u0443\u0440\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0437\u0430 APK \u0444\u0430\u0439\u043b\u043e\u0432\u0435, \u043a\u043e\u0438\u0442\u043e \u0441\u0430 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430" + }, + "ca": { + "summary": "utilitat per obtenir informaci\u00f3 sobre els arxius APK que estan instal\u00b7lades al d" + }, + "cs-CZ": { + "summary": "n\u00e1stroj pro z\u00edsk\u00e1v\u00e1n\u00ed informac\u00ed o APKs, kter\u00e9 jsou nainstalov\u00e1ny na va\u0161em za\u0159\u00edze" + }, + "da-DK": { + "summary": "hj\u00e6lpeprogram til at f\u00e5 oplysninger om APK'er der er installeret p\u00e5 din enhed\n" + }, + "de-DE": { + "description": "Checkey ist eine \u00f6ffentliche Dienstleistung um Informationen \u00fcber Anwendungen die auf deinem Ger\u00e4t installiert sind, zu bekommen. Beginne mit einer Liste mit allen Apps die du auf deinem Ger\u00e4t installiert hast, es zeigt sich dir die Applikations Signatur mit einer einfachen Ber\u00fchrung und bietet Links zu virustotal.com und androidobservatery,org um einfachen Zugriff auf die Profile der Applikation zu bekommen. Es erlaubt dir au\u00dferdem das signierte Zertifikat zu exportieren und einen Applikations Signatur Pin zu erzeugen f\u00fcr die Verwendung mit der TrustedIntends B\u00fccherei.\nWir s\nDu siehst deine Sprache nicht? Schlie\u00dfe dich uns an und \u00fcbersetze die App:\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n***Erfahren Sie mehr***\n\u2605 UNSERE WEBSEITE: https://GuardianProject.info\n\u2605 AUF TWITTER: https://twitter.com/guardianproject\nhttps://gitlab.com/guardianproject/checkey\n", + "name": "Checkey: Info \u00fcber lokale Apps", + "summary": "genutzt um Informationen \u00fcber die APKs zu bekommen auf deinem Ger\u00e4t installiert\n" + }, + "el-GR": { + "description": "\u03a4\u03bf Checkey \u03b5\u03af\u03bd\u03b1\u03b9 \u03ad\u03bd\u03b1 \u03b2\u03bf\u03b7\u03b8\u03b7\u03c4\u03b9\u03ba\u03cc \u03c0\u03c1\u03cc\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1 \u03b3\u03b9\u03b1 \u03c4\u03b7 \u03bb\u03ae\u03c8\u03b7 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03b9\u03ce\u03bd \u03c3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ac \u03bc\u03b5 \u03c4\u03b1 APK \u03c0\u03bf\u03c5 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03b3\u03ba\u03b1\u03c4\u03b5\u03c3\u03c4\u03b7\u03bc\u03ad\u03bd\u03b1 \u03c3\u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03c3\u03b1\u03c2. \u039e\u03b5\u03ba\u03b9\u03bd\u03ce\u03bd\u03c4\u03b1\u03c2 \u03bc\u03b5 \u03bc\u03b9\u03b1 \u03bb\u03af\u03c3\u03c4\u03b1 \u03cc\u03bb\u03c9\u03bd \u03c4\u03c9\u03bd \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ce\u03bd \u03c0\u03bf\u03c5 \u03ad\u03c7\u03b5\u03c4\u03b5 \u03b5\u03b3\u03ba\u03b1\u03c4\u03b1\u03c3\u03c4\u03ae\u03c3\u03b5\u03b9 \u03c3\u03c4\u03b7 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ae \u03c3\u03b1\u03c2, \u03b8\u03b1 \u03c3\u03b1\u03c2 \u03b4\u03b5\u03af\u03be\u03b5\u03b9 \u03c4\u03b7\u03bd \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae \u03c4\u03bf\u03c5 APK \u03bc\u03b5 \u03ad\u03bd\u03b1 \u03bc\u03cc\u03bd\u03bf \u03ac\u03b3\u03b3\u03b9\u03b3\u03bc\u03b1 \u03ba\u03b1\u03b9 \u03b8\u03b1 \u03c0\u03b1\u03c1\u03ad\u03c7\u03b5\u03b9 \u03c3\u03c5\u03bd\u03b4\u03ad\u03c3\u03bc\u03bf\u03c5\u03c2 \u03c3\u03c4\u03bf virustotal.com \u03ba\u03b1\u03b9 \u03c4\u03bf androidobservatory.org \u03b3\u03b9\u03b1 \u03b5\u03cd\u03ba\u03bf\u03bb\u03b7 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03c4\u03b1 \u03c0\u03c1\u03bf\u03c6\u03af\u03bb \u03b1\u03c5\u03c4\u03bf\u03cd \u03c4\u03bf\u03c5 APK. \u0398\u03b1 \u03c3\u03b1\u03c2 \u03b5\u03c0\u03b9\u03c4\u03c1\u03ad\u03c8\u03b5\u03b9 \u03b5\u03c0\u03af\u03c3\u03b7\u03c2 \u03bd\u03b1 \u03b5\u03be\u03ac\u03b3\u03b5\u03c4\u03b5 \u03c4\u03bf \u03c0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03b9\u03ba\u03cc \u03c5\u03c0\u03bf\u03b3\u03c1\u03b1\u03c6\u03ae\u03c2 \u03ba\u03b1\u03b9 \u03bd\u03b1 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ae\u03c3\u03b5\u03c4\u03b5 \u03b1\u03c1\u03c7\u03b5\u03af\u03b1 pin ApkSignaturePin \u03b3\u03b9\u03b1 \u03c7\u03c1\u03ae\u03c3\u03b7 \u03bc\u03b5 \u03c4\u03b7 \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7 TrustedIntents.\n\u2605 MI\u039bAME TH \u0393\u039b\u03a9\u03a3\u03a3\u0391 \u03c3\u03b1\u03c2: \u03a4\u03bf Checkey \u03b5\u03af\u03bd\u03b1\u03b9 \u03b4\u03b9\u03b1\u03b8\u03ad\u03c3\u03b9\u03bc\u03bf \u03b3\u03b9\u03b1 \u03c6\u03af\u03bb\u03bf\u03c5\u03c2 \u03c0\u03bf\u03c5 \u03bc\u03b9\u03bb\u03bf\u03cd\u03bd:\nDeutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk, portugu\u00eas (Portugal), \u0420\u0443\u0441\u0441\u043a\u0438\u0439, Sloven\u0161\u010dina, T\u00fcrk\u00e7e\n\u0394\u03b5\u03bd \u03b2\u03bb\u03ad\u03c0\u03b5\u03c4\u03b5 \u03c4\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1 \u03c3\u03b1\u03c2; \u0393\u03af\u03bd\u03b5\u03c4\u03b5 \u03bc\u03ad\u03bb\u03bf\u03c2 \u03ba\u03b1\u03b9 \u03b2\u03bf\u03b7\u03b8\u03ae\u03c3\u03c4\u03b5 \u03c3\u03c4\u03b7 \u03bc\u03b5\u03c4\u03ac\u03c6\u03c1\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae\u03c2:\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n***\u039c\u03ac\u03b8\u03b5\u03c4\u03b5 \u03a0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b1***\n\u2605 \u03a3\u03a7\u0395\u03a4\u0399\u039a\u0391 \u039c\u0395 \u0395\u039c\u0391\u03a3: \u03a4\u03bf Guardian Project \u03b5\u03af\u03bd\u03b1\u03b9 \u03bc\u03b9\u03b1 \u03bf\u03bc\u03ac\u03b4\u03b1 \u03b4\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03ce\u03bd \u03c0\u03bf\u03c5 \u03ba\u03ac\u03bd\u03bf\u03c5\u03bd \u03b1\u03c3\u03c6\u03b1\u03bb\u03b5\u03af\u03c2 \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ad\u03c2 \u03b3\u03b9\u03b1 \u03ba\u03b9\u03bd\u03b7\u03c4\u03ac \u03ba\u03b1\u03b9 open-source \u03ba\u03ce\u03b4\u03b9\u03ba\u03b1 \u03b3\u03b9\u03b1 \u03ad\u03bd\u03b1 \u03ba\u03b1\u03bb\u03cd\u03c4\u03b5\u03c1\u03bf \u03b1\u03cd\u03c1\u03b9\u03bf\n\u2605 \u0397 \u0399\u03a3\u03a4\u039f\u03a3\u0395\u039b\u0399\u0394\u0391 \u039c\u0391\u03a3: https://GuardianProject.info\n\u2605 \u03a3\u03a4\u039f TWITTER: https://twitter.com/guardianproject\n\u2605 \u0395\u039b\u0395\u03a5\u0398\u0395\u03a1\u039f \u039b\u039f\u0393\u0399\u03a3\u039c\u0399\u039a\u039f: \u03a4\u03bf Checkey \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bb\u03b5\u03cd\u03b8\u03b5\u03c1\u03bf \u03bb\u03bf\u03b3\u03b9\u03c3\u03bc\u03b9\u03ba\u03cc. \u039c\u03c0\u03bf\u03c1\u03b5\u03af\u03c4\u03b5 \u03bd\u03b1 \u03c1\u03af\u03be\u03c4\u03b5 \u03bc\u03b9\u03b1 \u03bc\u03b1\u03c4\u03b9\u03ac \u03c3\u03c4\u03bf\u03bd \u03c0\u03b7\u03b3\u03b1\u03af\u03bf \u03ba\u03ce\u03b4\u03b9\u03ba\u03b1 \u03bc\u03b1\u03c2 \u03ae \u03b3\u03af\u03bd\u03b5\u03c4\u03b5 \u03bc\u03ad\u03bb\u03bf\u03c2 \u03c4\u03b7\u03c2 \u03ba\u03bf\u03b9\u03bd\u03cc\u03c4\u03b7\u03c4\u03ac\u03c2 \u03bc\u03b1\u03c2 \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03ba\u03ac\u03bd\u03bf\u03c5\u03bc\u03b5 \u03c4\u03bf Checkey \u03b1\u03ba\u03cc\u03bc\u03b1 \u03ba\u03b1\u03bb\u03cd\u03c4\u03b5\u03c1\u03bf:\nhttps://gitlab.com/guardianproject/checkey\n\u2605 \u03a3\u03a4\u0395\u0399\u039b\u03a4\u0395 \u039c\u0391\u03a3 \u039c\u0397\u039d\u03a5\u039c\u0391: \u039c\u03b1\u03c2 \u03bb\u03b5\u03af\u03c0\u03b5\u03b9 \u03c4\u03bf \u03b1\u03b3\u03b1\u03c0\u03b7\u03bc\u03ad\u03bd\u03bf \u03c3\u03b1\u03c2 \u03c7\u03b1\u03c1\u03b1\u03ba\u03c4\u03b7\u03c1\u03b9\u03c3\u03c4\u03b9\u03ba\u03cc; \u0392\u03c1\u03ae\u03ba\u03b1\u03c4\u03b5 \u03ad\u03bd\u03b1 \u03b5\u03bd\u03bf\u03c7\u03bb\u03b7\u03c4\u03b9\u03ba\u03cc \u03c3\u03c6\u03ac\u03bb\u03bc\u03b1; \u03a0\u03b5\u03af\u03c4\u03b5 \u03bc\u03b1\u03c2! \u0398\u03b1 \u03b8\u03ad\u03bb\u03b1\u03bc\u03b5 \u03bd\u03b1 \u03c3\u03b1\u03c2 \u03b1\u03ba\u03bf\u03cd\u03c3\u03bf\u03c5\u03bc\u03b5. \u03a3\u03c4\u03b5\u03af\u03bb\u03c4\u03b5 \u03bc\u03b1\u03c2 \u03ad\u03bd\u03b1 \u03bc\u03ae\u03bd\u03c5\u03bc\u03b1 \u03c3\u03c4\u03bf: support@guardianproject.info \u03ae \u03b2\u03c1\u03b5\u03af\u03c4\u03b5 \u03bc\u03b1\u03c2 \u03c3\u03c4\u03bf chat room https://guardianproject.info/contact\n", + "name": "Checkey: \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03b5\u03c6\u03b1\u03c1\u03bc\u03bf\u03b3\u03ce\u03bd", + "summary": "\u03b2\u03bf\u03b7\u03b8\u03b7\u03c4\u03b9\u03ba\u03cc \u03c0\u03c1\u03cc\u03b3\u03c1\u03b1\u03bc\u03bc\u03b1 \u03b3\u03b9\u03b1 \u03c4\u03b7 \u03bb\u03ae\u03c8\u03b7 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03b9\u03ce\u03bd \u03c3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ac \u03bc\u03b5 \u03c4\u03b1 \u03b5\u03b3\u03ba\u03b1\u03c4\u03b5\u03c3\u03c4\u03b7\u03bc\u03ad\u03bd\u03b1 APK \u03c3\u03b1\u03c2\n" + }, + "en-US": { + "description": "Checkey is a utility for getting information about the APKs that are installed on your device. Starting with a list of all of the apps that you have installed on your device, it will show you the APK signature with a single touch, and provides links to virustotal.com and androidobservatory.org to easily access the profiles of that APK. It will also let you export the signing certificate and generate ApkSignaturePin pin files for use with the TrustedIntents library.\n\n\u2605 OPEN-SOURCE: Our code is transparent. You can take a look or join the community to help make Checkey even better: https://gitlab.com/guardianproject/checkey\n\u2605 WE SPEAK YOUR LANGUAGE: Checkey is available for friends who speak: Deutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk, portugu\u00eas (Portugal), \u0420\u0443\u0441\u0441\u043a\u0438\u0439, Sloven\u0161\u010dina, T\u00fcrk\u00e7e\n\nDon\u2019t see your language? Join us and help translate the app:\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n\n***Learn More***\n\u2605 ABOUT US: Guardian Project is a group of developers that make secure mobile apps and open-source code for a better tomorrow\n\u2605 OUR WEBSITE: https://GuardianProject.info to learn more about us\n\u2605 ON TWITTER: https://twitter.com/guardianproject\n\u2605 FREE SOFTWARE: Checkey is free software. You can take a look at our source code, or contribute to help make Checkey even better: https://gitlab.com/guardianproject/checkey\n\u2605 MESSAGE US: Are we missing your favorite feature? Found an annoying bug? Please tell us! We\u2019d love to hear from you. Send us an email: support@guardianproject.info or find us in our chat room https://guardianproject.info/contact\n", + "featureGraphic": "featureGraphic.png", + "icon": "icon.png", + "name": "Checkey: info on local apps\n", + "phoneScreenshots": [ + "First.png", + "WZgIkxH4IACsYCLBy49XzLUBkl_TAcUtIefuO_TQOlDmp8znPLEFsv_c2WniSzqWDA.png", + "YCYv6nqOg_oXuBFTDxcu9Tp4Qe_hMa9ndEa_5oOWwugjlHRo5sUe1fHXhRk4jkojdb8.png", + "checkey-phone.png", + "checkey.png" + ], + "sevenInchScreenshots": [ + "checkey-tablet.png" + ], + "summary": "utility for getting information about the APKs that are installed on your device", + "whatsNew": "+ reproducible build\n+ add translations: fa fr zh-CN\n+ update translations: de pt_PT tr\n" + }, + "es-ES": { + "description": "Checkey es una utilidad para obtener informaci\u00f3n acerca de los APKs que \nest\u00e1n instalados en su dispositivo. Comenzando por una lista de todas las \naplicaciones que ha instalado en su dispositivo, le mostrar\u00e1 la firma del \nAPK con una simple pulsaci\u00f3n, y proporciona enlaces a virustotal.com y \nandroidobservatory.org para facilitar el acceso a los perfiles de ese APK. \nAdem\u00e1s esto le permite exportar el certificado firmante y generar ficheros \npin de ApkSignaturePin para su uso con la librer\u00eda TrustedIntents.\n\n\u2605 HABLAMOS SU IDIOMA: Checkey est\u00e1 disponible para los amigos que hablan: Deutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk, T\u00fcrk\u00e7e\n\n\u00bfNo ve su idioma? \u00danase a nosotros y ayude a traducir la aplicaci\u00f3n:\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n\n***Aprenda m\u00e1s***\n\n\u2605 ABOUT US: Guardian Project is a group of developers that make secure \nmobile apps and open-source code for a better tomorrow\n\n\u2605 ACERCA DE NOSOTROS: Guardian Project es un grupo de desarrolladores que \nelaboran aplicaciones m\u00f3viles seguras y de c\u00f3digo abierto para un mejor \nma\u00f1ana\n\n\u2605 NUESTRO SITIO WEB: https://GuardianProject.info\n\n\u2605 EN TWITTER: https://twitter.com/guardianproject\n\n\u2605 SOFTWARE LIBRE: Checkey es software libre. Puede echar un vistazo a \nnuestro c\u00f3digo fuente, o contribuir a hacer Checkey incluso mejor:\nhttps://gitlab.com/guardianproject/checkey\n\n\u2605 ENV\u00cdENOS UN MENSAJE: \u00bfNos hemos olvidado de su caracter\u00edstica favorita? \n\u00bfEncontr\u00f3 alg\u00fan fallo molesto? \u00a1Por favor cu\u00e9ntenoslo! Nos encantar\u00e1 \nescucharlo de usted. Env\u00edenos un correo electr\u00f3nico: \nsupport@guardianproject.info o encu\u00e9ntrenos en nuestra sala de chat \nhttps://guardianproject.info/contact\n", + "name": "Checkey: Info de apps locales\n", + "summary": "utilidad para obtener informaci\u00f3n sobre los APKs instalados en su dispositivo" + }, + "et": { + "summary": "kasuliku info saamine APK-d, mis on seadmesse installitud" + }, + "fi-FI": { + "description": "Checkey on apuohjelma, jolla saa tietoja laiteeseen asennetuista APK-pakkaustiedostoista. Ohjelma luettelee aluksi kaikki laitteeseen asennetut sovellukset ja n\u00e4ytt\u00e4\u00e4 APK-allekirjoituksen yhdell\u00e4 kosketuksella sek\u00e4 tarjoaa linkit virustotal.com- ja androidobservatory.com-sivuistoille, joilta saa helposti kyseisen APK-pakkaustiedoston profiilit. Ohjelma sallii sinun my\u00f6s vied\u00e4 allekirjoitusvarmenteen ja tuottaa ApkSignaturePin-pin-tieodostoja k\u00e4ytett\u00e4v\u00e4ksi TrustedIntents-kirjastossa. \n\u2605 PUHUMME KIELT\u00c4SI: Checkey on saataville yst\u00e4ville, jotka puhuvat seuraavia kieli\u00e4:\nDeutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk, portugu\u00eas (Portugal), \u0420\u0443\u0441\u0441\u043a\u0438\u0439, Sloven\u0161\u010dina, T\u00fcrk\u00e7e\nEtk\u00f6 n\u00e4e kielt\u00e4si? Liity meihin ja auta sovelluksen kotoistamisessa:\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n***Opi lis\u00e4\u00e4***\n\u2605 TIETOA MEIST\u00c4: Guardian Project on kehitt\u00e4jien ryhm\u00e4, joka tekee turvallisia mobiilisovelluksia ja avointa l\u00e4hdekoodia parempaa huomista varten\n\u2605 WEBBISIVUMME: https://GuardianProject.info\n\u2605 TWITTERISS\u00c4: https://twitter.com/guardianproject\n\u2605 ILMAINEN OHJELMA: Checkey on ilmainen ohjelma. Voit vilkaista l\u00e4hdekoodia tai avustaa Checkey-ohjelman tekemiseksi viel\u00e4 paremmaksi:\nhttps://gitlab.com/guardianproject/checkey\n\u2605 VIESTIT\u00c4 MEILLE: Kaipaatko suosikkiominaisuuttasi? L\u00f6ysitk\u00f6 harmillisen ohjelmointivirheen? Kerro meille! Kuulemme sinusta mielell\u00e4\u00e4n. L\u00e4het\u00e4 meille s\u00e4hk\u00f6postia: support@guardianproject.info tai etsi meid\u00e4t juttelukanavalla https://guardianproject.info/contact\n", + "name": "Checkey: tietoa sovelluksista\n", + "summary": "ohjelma tietojen hakemiseksi laitteeseesi asennetuista APK-pakkaustiedostoista\n" + }, + "fr-CA": { + "featureGraphic": "featureGraphic.png" + }, + "fr-FR": { + "description": "Checkey est un utilitaire permettant de recueillir des informations sur les APK install\u00e9s sur votre appareil. En partant d'une liste de toutes les applis install\u00e9es sur votre appareil, V\u00e9ricl\u00e9 vous pr\u00e9sentera la signature de l'APK en un seul toucher, et vous offrira des liens vers virustotal.com et androidobservatory.org afin d'acc\u00e9der ais\u00e9ment aux profils de cet APK. Il vous permettra aussi d'exporter le certificat de signature et de g\u00e9n\u00e9rer des fichiers NIP ApkSignaturePin pour les utiliser avec la biblioth\u00e8que TrustedIntents.\n\u2605 NOUS PARLONS VOTRE LANGUE : Checkey est propos\u00e9 \u00e0 nos amis parlant :\nDeutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk bokm\u00e5l, portugu\u00eas (Portugal), \u0420\u0443\u0441\u0441\u043a\u0438\u0439, Sloven\u0161\u010dina, T\u00fcrk\u00e7e, fran\u00e7ais\nVous ne voyez pas votre langue ? Rejoignez-nous et aidez-nous \u00e0 traduire l'appli :\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n***En apprendre davantage***\n\u2605 \u00c0 PROPOS DE NOUS : le Projet Guardian est un groupe de d\u00e9veloppeurs cr\u00e9ant des applis mobiles s\u00e9curis\u00e9es et du code ouvert pour des lendemains meilleurs.\n\u2605 NOTRE SITE WEB : https://GuardianProject.info\n\u2605 SUR TWITTER: https://twitter.com/guardianproject\n\u2605 LOGICIEL LIBRE : Checkey est un logiciel libre. Vous pouvez regarder notre code source, ou contribuer en aidant \u00e0 encore am\u00e9liorer Checkey :\nhttps://gitlab.com/guardianproject/checkey\n\u2605 CONTACTEZ-NOUS : votre fonction favorite est-elle absente ? Avez-vous avez trouv\u00e9 un bogue g\u00eanant ? Nous aimerions que vous nous en fassiez part ! Envoyez-nous un courriel : support@guardianproject.info ou trouvez-nous dans notre salon de discussion https://guardianproject.info/contact\n", + "featureGraphic": "featureGraphic.png", + "icon": "icon.png", + "name": "Checkey : infos applis locales", + "sevenInchScreenshots": [ + "checkey-tablet.png" + ], + "summary": "utilitaire pour obtenir des informations sur les APKs qui sont install\u00e9s sur vot" + }, + "hi-IN": { + "summary": "\u0906\u092a\u0915\u0947 \u0921\u093f\u0935\u093e\u0907\u0938 \u092a\u0930 \u0938\u094d\u0925\u093e\u092a\u093f\u0924 \u0915\u0930 \u0930\u0939\u0947 \u0939\u0948\u0902 \u0915\u093f APKs \u0915\u0947 \u092c\u093e\u0930\u0947 \u092e\u0947\u0902 \u091c\u093e\u0928\u0915\u093e\u0930\u0940 \u092a\u094d\u0930\u093e\u092a\u094d\u0924 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093f" + }, + "hr": { + "summary": "alat za dobivanje informacija o APK-ovi koji su instalirani na va\u0161em ure\u0111aju" + }, + "hu-HU": { + "summary": "seg\u00e9dprogram egyre inform\u00e1ci\u00f3t APK, hogy telep\u00edtve van a k\u00e9sz\u00fcl\u00e9ken\n" + }, + "id": { + "summary": "utilitas untuk mendapatkan informasi tentang APK yang diinstal pada perangkat An" + }, + "it-IT": { + "summary": "utility per ottenere informazioni sulle APKs installati sul dispositivo\n" + }, + "ja-JP": { + "description": "Checkey \u306f\u3001\u304a\u4f7f\u3044\u306e\u30c7\u30d0\u30a4\u30b9\u306b\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3055\u308c\u3066\u3044\u308b APK \u306e\u60c5\u5831\u3092\u53d6\u5f97\u3059\u308b\u30e6\u30fc\u30c6\u30a3\u30ea\u30c6\u30a3\u3067\u3059\u3002\u304a\u4f7f\u3044\u306e\u30c7\u30d0\u30a4\u30b9\u306b\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3055\u308c\u305f\u3059\u3079\u3066\u306e\u30a2\u30d7\u30ea\u306e\u30ea\u30b9\u30c8\u3092\u306f\u3058\u3081\u3001\u30ef\u30f3\u30bf\u30c3\u30c1\u3067 APK \u30b7\u30b0\u30cd\u30c1\u30e3\u3092\u8868\u793a\u3057\u305f\u308a\u3001virustotal.com \u3068 androidobservatory.org \u3078\u306e\u30ea\u30f3\u30af\u3092\u63d0\u4f9b\u3057\u3066\u3001\u7c21\u5358\u306b APK \u306e\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb\u306b\u30a2\u30af\u30bb\u30b9\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u307e\u305f\u3001\u7f72\u540d\u8a3c\u660e\u66f8\u306e\u30a8\u30af\u30b9\u30dd\u30fc\u30c8\u3001TrustedIntents \u30e9\u30a4\u30d6\u30e9\u30ea\u3067\u4f7f\u7528\u3059\u308b ApkSignaturePin \u30d4\u30f3\u30d5\u30a1\u30a4\u30eb\u306e\u751f\u6210\u304c\u3067\u304d\u307e\u3059\u3002\n\u2605 \u3042\u306a\u305f\u306e\u8a00\u8a9e\u3067\u304a\u4f7f\u3044\u3044\u305f\u3060\u3051\u307e\u3059: Checkey \u306f\u6b21\u306e\u8a00\u8a9e\u3092\u8a71\u3059\u53cb\u3060\u3061\u304c\u5229\u7528\u3067\u304d\u307e\u3059:\nDeutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk, portugu\u00eas (Portugal), \u0420\u0443\u0441\u0441\u043a\u0438\u0439, Sloven\u0161\u010dina, T\u00fcrk\u00e7e\n\u3042\u306a\u305f\u306e\u8a00\u8a9e\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u304b? \u79c1\u305f\u3061\u306b\u53c2\u52a0\u3057\u3066\u3001\u30a2\u30d7\u30ea\u306e\u7ffb\u8a33\u3092\u652f\u63f4\u3057\u3066\u304f\u3060\u3055\u3044:\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n***\u3055\u3089\u306b\u8a73\u3057\u304f***\n\u2605 \u79c1\u305f\u3061\u306b\u3064\u3044\u3066: Guardian Project \u306f\u3001\u3088\u308a\u826f\u3044\u660e\u65e5\u306e\u305f\u3081\u306b\u3001\u5b89\u5168\u306a\u30e2\u30d0\u30a4\u30eb \u30a2\u30d7\u30ea\u3084\u30aa\u30fc\u30d7\u30f3 \u30bd\u30fc\u30b9 \u30b3\u30fc\u30c9\u3092\u4f5c\u308b\u958b\u767a\u8005\u306e\u30b0\u30eb\u30fc\u30d7\u3067\u3059\n\u2605 WEB\u30b5\u30a4\u30c8: https://GuardianProject.info\n\u2605 TWITTER: https://twitter.com/guardianproject\n\u2605 \u30d5\u30ea\u30fc\u30bd\u30d5\u30c8\u30a6\u30a7\u30a2: Checkey \u306f\u30d5\u30ea\u30fc\u30bd\u30d5\u30c8\u30a6\u30a7\u30a2\u3067\u3059\u3002\u79c1\u305f\u3061\u306e\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u3092\u898b\u305f\u308a\u3001Checkey \u3092\u3055\u3089\u306b\u826f\u304f\u3059\u308b\u624b\u52a9\u3051\u306b\u8ca2\u732e\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059:\nhttps://gitlab.com/guardianproject/checkey\n\u2605 \u79c1\u305f\u3061\u306b\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u304a\u9001\u308a\u304f\u3060\u3055\u3044: \u3042\u306a\u305f\u306e\u304a\u6c17\u306b\u5165\u308a\u306e\u6a5f\u80fd\u304c\u4e0d\u8db3\u3057\u3066\u3044\u307e\u305b\u3093\u304b? \u8ff7\u60d1\u306a\u30d0\u30b0\u3092\u767a\u898b\u3055\u308c\u307e\u3057\u305f\u304b? \u3054\u9023\u7d61\u304f\u3060\u3055\u3044! \u79c1\u305f\u3061\u306f\u3042\u306a\u305f\u306e\u3054\u610f\u898b\u3092\u304a\u5f85\u3061\u3057\u3066\u3044\u307e\u3059\u3002\u79c1\u305f\u3061\u306b\u30e1\u30fc\u30eb\u3092\u304a\u9001\u308a\u304f\u3060\u3055\u3044: support@guardianproject.info \u307e\u305f\u306f\u79c1\u305f\u3061\u306e\u30c1\u30e3\u30c3\u30c8\u30eb\u30fc\u30e0 https://guardianproject.info/contact \u304b\u3089\n", + "name": "Checkey: \u30ed\u30fc\u30ab\u30eb\u30a2\u30d7\u30ea\u306e\u60c5\u5831\n", + "summary": "\u304a\u4f7f\u3044\u306e\u30c7\u30d0\u30a4\u30b9\u306b\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3055\u308c\u3066\u3044\u308b APK \u306e\u60c5\u5831\u3092\u53d6\u5f97\u3059\u308b\u30e6\u30fc\u30c6\u30a3\u30ea\u30c6\u30a3\n" + }, + "ko-KR": { + "description": "Checkey\uc740 \uc7a5\uce58\uc5d0 \uc124\uce58\ub41c APK\uc5d0 \ub300\ud55c \uc815\ubcf4\ub97c \uc5bb\uae30\uc704\ud55c \uc720\ud2f8\ub9ac\ud2f0\uc785\ub2c8\ub2e4. \uc2dc\uc791\ud558\uac8c\ub418\uba74 \uc7a5\uce58\uc5d0 \uc124\uce58\ud55c \ubaa8\ub4e0 \uc571 \ubaa9\ub85d\uc744 \ubcf4\uc5ec\uc8fc\uace0, \ud55c\ubc88\uc758 \ud130\uce58\ub85c APK \uc11c\uba85\uc744 \ubcf4\uc5ec\uc8fc\uace0, APK\uc758 \ud504\ub85c\ud30c\uc77c\uc5d0 \uc27d\uac8c \uc811\uadfc\ud558\uc5ec virustotal.com \ubc0f androidobservatory.org\uc5d0 \ub300\ud55c \ub9c1\ud06c\ub97c \uc81c\uacf5\ud569\ub2c8\ub2e4. \uc11c\uba85 \uc778\uc99d\uc11c\ub97c \ub0b4\ubcf4\ub0b4\uace0 TrustedIntents \ub77c\uc774\ube0c\ub7ec\ub9ac\ub97c \uc0ac\uc6a9\ud558\uc5ec ApkSignaturePin \ud540 \ud30c\uc77c\uc744 \uc0dd\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.\n\n***\ub354 \uc790\uc138\ud788 \uc54c\uae30***\n\u2605 \uc6b0\ub9ac \uc6f9\uc0ac\uc774\ud2b8: https://GuardianProject.info\n\u2605 \ud2b8\uc704\ud130: https://twitter.com/guardianproject\n", + "name": "Checkey: \ub85c\uceec \uc571\uc5d0 \ub300\ud55c \uc815\ubcf4 \uc5bb\uae30\n", + "summary": "\ub2f9\uc2e0\uc758 \uc7a5\uce58\uc5d0 \uc124\uce58\ub418\uc5b4\uc788\ub294 APK\uac00\uc5d0 \ub300\ud55c \uc815\ubcf4\ub97c \ucde8\ub4dd\ud558\uae30\uc704\ud55c \uc720\ud2f8\ub9ac\ud2f0\n" + }, + "lt": { + "summary": "\u012frankis gauti informacij\u0105 apie APK, kad yra \u012fdiegtas j\u016bs\u0173 prietaise" + }, + "lv": { + "summary": "lietder\u012bba, lai ieg\u016btu inform\u0101ciju par APKs kas ir instal\u0113ti j\u016bsu ier\u012bc\u0113" + }, + "nl-NL": { + "summary": "hulpprogramma voor het verkrijgen van informatie over de APK die zijn ge\u00efnstalle" + }, + "no-NO": { + "description": "Checkey er et verkt\u00f8y for innhenting av informasjon om APK-er installert p\u00e5 din enhet. I f\u00f8rstningen en liste over installerte program, hvis APK-signatur er ett trykk unna. Dernest lenker til virustotal.com og androidobservatory.org for profilering av valgt APK. Programmet lar deg ogs\u00e5 eksportere signeringssertifikatet og generere ApkSignaturePin pin-kodefiler for bruk med TrustedIntents-biblioteket.\n\u2605 VI SNAKKER DITT SPR\u00c5K: Checkeys vennegjeng omfatter:\nDeutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk bokm\u00e5l, portugu\u00eas (Portugal), \u0420\u0443\u0441\u0441\u043a\u0438\u0439, Sloven\u0161\u010dina, T\u00fcrk\u00e7e\n\n(Tysk, Engelsk, Spansk, Finsk, Japansk, Koreansk, Norsk bokm\u00e5l, Portugisisk (Portugal), Russisk, Slovensk, Tyrkisk)\nMangler ditt spr\u00e5k? Hjelp oss \u00e5 oversette programmet:\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n***L\u00e6r mer***\n\u2605 OM OSS: Guardianprosjektet er en gruppe utviklere som lager sikre mobilprogrammer og friprog-kode for en bedre fremtid.\n\u2605 V\u00c5R NETTSIDE: https://GuardianProject.info\n\u2605 DESSVERRE P\u00c5 TWITTER: https://twitter.com/guardianproject\n\u2605 FRI PROGRAMVARE: Checkey er fri programvare. Du kan sjekke ut v\u00e5r programkode, og bidra til den for \u00e5 gj\u00f8re Checkey enda bedre:\nhttps://gitlab.com/guardianproject/checkey\n\u2605 TILBAKEMELDINGER: Mangler vi din favorittfunksjonalitet? Har du funnet en irriterende feil. Fortell oss om det! Vi elsker \u00e5 lytte til god kritikk. Send oss en e-post support@guardianproject.info eller finn oss i v\u00e5r sludrekanal https://guardianproject.info/contact\n", + "name": "Checkey: Info om lokale apper\n", + "summary": "verkt\u00f8y for innhenting av informasjon om APK-ene som er installert p\u00e5 din enhet\n", + "whatsNew": "+ Gjentagbar byggeprosess\n+ Oversettelser lagt til: fa fr zh-CN\n+ Oppdaterte oversettelser: de pt_PT tr\n" + }, + "pl-PL": { + "summary": "narz\u0119dzie do uzyskiwania informacji o APKs, kt\u00f3re s\u0105 zainstalowane w urz\u0105dzeniu\n" + }, + "pt-BR": { + "description": "Checkey \u00e9 um utilit\u00e1rio para obter informa\u00e7\u00e3o sobre as APKs que est\u00e3o instaladas no seu dispositivo. Come\u00e7ando com uma lista de todas as apps que est\u00e3o instaladas no seu dispositivo. Esta ir\u00e1 mostrar-lhe a assinatura APK com um \u00fanico toque, e proporciona hiperliga\u00e7\u00f5es para virustotal.com e androidobservatory.org para aceder facilmente aos perfis dessa APK. Esta tamb\u00e9m ir\u00e1 deix\u00e1-lo exportar o certificado de assinatura e gerar os ficheiros c\u00f3digo ApkSignaturePin para usar com a biblioteca TrustedIntents.\n\n\u2605 N\u00d3S FALAMOS O SEU IDIOMA: Checkey est\u00e1 dispon\u00edvel para os amigos que falam: Deutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk, portugu\u00eas (Portugal), \u0420\u0443\u0441\u0441\u043a\u0438\u0439, Sloven\u0161\u010dina, T\u00fcrk\u00e7e\nN\u00e3o v\u00ea o seu idioma? Junte-se a n\u00f3s e ajude a traduzir a app:\nhttps://hosted.weblate.org/translate/guardianproject/\n\n***Saiba Mais***\n\u2605 SOBRE N\u00d3S: Guardian Project \u00e9 um grupo de respons\u00e1veis pelo desenvolvimento que cria apps m\u00f3veis seguras e de c\u00f3digo aberto para um futuro melhor.\n\u2605 O NOSSO S\u00cdTIO DA WEB: https://GuardianProject.info\n\u2605 NO TWITTER: https://twitter.com/guardianproject\n\u2605 PROGRAMA LIVRE: Checkey \u00e9 um programa gratuito. Pode dar uma vista de olhos no nosso c\u00f3digo aberto, ou contribuir para ajudar a tornar Checkey ainda melhor:\nhttps://gitlab.com/guardianproject/checkey\n\u2605 ENVIE-NOS UMA MENSAGEM: N\u00f3s estamos a perder a sua fun\u00e7\u00e3o favorita? Encontrou um bug aborrecido? Por favor, diga-nos! N\u00f3s gostar\u00edamos de o ouvir. Envie-nos uma mensagem: support@guardianproject.info ou encontre-nos na nossa sala de conversa\u00e7\u00e3o em https://guardianproject.info/contact\n", + "name": "Checkey: info sobre app locais", + "summary": "Utilit\u00e1rio para obter informa\u00e7\u00e3o sobre as APKs instaladas no seu dispositivo" + }, + "pt-PT": { + "description": "Checkey \u00e9 um utilit\u00e1rio para obter informa\u00e7\u00e3o sobre as APKs que est\u00e3o instaladas no seu dispositivo. Come\u00e7ando com uma lista de todas as apps que est\u00e3o instaladas no seu dispositivo, esta ir\u00e1 mostrar-lhe a assinatura APK com um \u00fanico toque, e proporciona hiperliga\u00e7\u00f5es para virustotal.com e androidobservatory.org para aceder facilmente aos perfis dessa APK. Tamb\u00e9m permite exportar o certificado de assinatura e gerar os ficheiros de c\u00f3digo PIN ApkSignaturePin para usar com a biblioteca TrustedIntents.\n\n\u2605 C\u00d3DIGO-FONTE ABERTO: o nosso c\u00f3digo \u00e9 transparente. Pode dar uma vista de olhos ou juntar-se \u00e0 comunidade para tornar o Checkey ainda melhor: https://gitlab.com/guardianproject/checkey\n\u2605 N\u00d3S FALAMOS O SEU IDIOMA: o Checkey est\u00e1 dispon\u00edvel para as pessoas que falam: alem\u00e3o, ingl\u00eas, espanhol, finland\u00eas, japon\u00eas, coreano, noruegu\u00eas, portugu\u00eas, portugu\u00eas (Brasil), russo, esloveno, turco.\n\nN\u00e3o v\u00ea o seu idioma? Junte-se a n\u00f3s e ajude a traduzir a app: https://hosted.weblate.org/translate/guardianproject/\n\n***Saiba mais***\n\u2605 SOBRE N\u00d3S: Guardian Project \u00e9 um grupo de respons\u00e1veis pelo desenvolvimento que cria apps m\u00f3veis seguras e de c\u00f3digo aberto para um futuro melhor.\n\u2605 O NOSSO S\u00cdTIO DA WEB: https://GuardianProject.info\n\u2605 NO TWITTER: https://twitter.com/guardianproject\n\u2605 PROGRAMA LIVRE: Checkey \u00e9 um programa gratuito. Pode dar uma vista de olhos no nosso c\u00f3digo-fonte aberto, ou contribuir para ajudar a tornar o Checkey ainda melhor:\nhttps://gitlab.com/guardianproject/checkey\n\u2605 ENVIE-NOS UMA MENSAGEM: n\u00f3s estamos a perder a sua funcionalidade favorita? Encontrou um erro chato? Por favor, diga-nos! N\u00f3s gostar\u00edamos de o ouvir. Envie-nos uma mensagem: support@guardianproject.info ou encontre-nos na nossa sala de conversa\u00e7\u00e3o em https://guardianproject.info/contact\n", + "name": "Checkey: info sobre app locais", + "summary": "Utilit\u00e1rio para obter informa\u00e7\u00e3o sobre as APKs instaladas no seu dispositivo", + "whatsNew": "+ compila\u00e7\u00e3o reprodut\u00edvel\n+ adicionar tradu\u00e7\u00f5es: fa fr zh-CN\n+ atualizar tradu\u00e7\u00f5es: de pt_PT tr\n" + }, + "ro": { + "summary": "utilitate pentru a ob\u021bine informa\u021bii despre fi\u0219iere APK care sunt instalate pe d" + }, + "ru-RU": { + "description": "Checkey \u044d\u0442\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e APK \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b \u043d\u0430 \u0412\u0430\u0448\u0435\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435. \u041d\u0430\u0447\u0438\u043d\u0430\u044f \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u0441\u0435\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b\u0445 \u043d\u0430 \u0412\u0430\u0448\u0435\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u043e\u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u0438 APK \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443 \u043a\u0430\u0441\u0430\u043d\u0438\u044e \u0438 \u0443\u043a\u0430\u0436\u0435\u0442 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 virustotal.com \u0438 androidabservatory.org \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043f\u0440\u043e\u0444\u0438\u043b\u044f\u043c \u044d\u0442\u0438\u0445 APK. \u041e\u043d\u0430 \u0442\u0430\u043a \u0436\u0435 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u043c\u0435\u0440\u0430 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0432 \u0438 \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u0444\u0430\u0439\u043b\u044b \u043d\u043e\u043c\u0435\u0440\u043e\u0432 ApkSignaturePin \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 TrustedIntents.\n* \u041c\u042b \u0413\u041e\u0412\u041e\u0420\u0418\u041c \u041d\u0410 \u0412\u0410\u0428\u0415\u041c \u042f\u0417\u042b\u041a\u0415: Checkey \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0434\u043b\u044f \u0434\u0440\u0443\u0437\u0435\u0439 \u0433\u043e\u0432\u043e\u0440\u044f\u0449\u0438\u0445 \u043d\u0430:\n\u041d\u0435 \u0432\u0438\u0434\u0438\u0442\u0435 \u0432\u0430\u0448\u0435\u0433\u043e \u044f\u0437\u044b\u043a\u0430? \u0421\u0432\u044f\u0436\u0438\u0442\u0435\u0441\u044c \u0441 \u043d\u0430\u043c\u0438 \u0438 \u043f\u043e\u043c\u043e\u0433\u0438\u0442\u0435 \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435:\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n***\u0423\u0437\u043d\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435***\n* \u041e \u041d\u0410\u0421: Guardian Project \u044d\u0442\u043e \u0433\u0440\u0443\u043f\u043f\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0434\u0435\u043b\u0430\u044e\u0449\u0430\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u0431\u0443\u0434\u0443\u0449\u0435\u0433\u043e.\n\u2605 \u041d\u0410\u0428 WEBSITE: https://GuardianProject.info\n\u2605 \u0412 TWITTER: https://twitter.com/guardianproject\n\u2605 \u041f\u0420\u041e\u0413\u0420\u0410\u041c\u041c\u041d\u041e\u0415 \u041e\u0411\u0415\u0421\u041f\u0415\u0427\u0415\u041d\u0418\u0415 \u0421 \u041e\u0422\u041a\u0420\u042b\u0422\u042b\u041c \u0418\u0421\u0425\u041e\u0414\u041d\u042b\u041c \u041a\u041e\u0414\u041e\u041c: Checkey \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u043c \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435\u043c \u0441 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043d\u0430\u0448 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438\u043b\u0438 \u043f\u043e\u043c\u043e\u0447\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c Checkey \u0435\u0449\u0451 \u043b\u0443\u0447\u0448\u0435:\nhttps://gitlab.com/guardianproject/checkey\n\u2605 \u0414\u0410\u0419\u0422\u0415 \u041d\u0410\u041c \u0417\u041d\u0410\u0422\u042c: \u041c\u044b \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u043b\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0412\u0430\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b? \u0412\u044b \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0443? \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0434\u0430\u0439\u0442\u0435 \u043d\u0430\u043c \u0437\u043d\u0430\u0442\u044c! \u041c\u044b \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u0438 \u0440\u0430\u0441\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0412\u0430\u0441. \u041f\u0440\u0438\u0448\u043b\u0438\u0442\u0435 \u043d\u0430\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0447\u0442\u0443: support@guardianproject.info \u0438\u043b\u0438 \u043d\u0430\u0431\u0435\u0440\u0438\u0442\u0435 \u043d\u0430\u0441 \u0432 \u0447\u0430\u0442\u0435 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 https://guardianproject.info/contact\n", + "name": "Checkey: \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b\n", + "summary": "\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0434\u043b\u044f \u0441\u0431\u043e\u0440\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431 APK \u041a\u041e\u0422\u041e\u0420\u042b\u0415 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b \u043d\u0430 \u0412\u0430\u0448\u0435\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435\n" + }, + "sk": { + "summary": "n\u00e1stroj pre z\u00edskavanie inform\u00e1ci\u00ed o APKs, ktor\u00e9 s\u00fa nain\u0161talovan\u00e9 na va\u0161om zariad" + }, + "sl": { + "description": "Checkey je orodje za pridobivanje informacij o APK paketih, ki so name\u0161\u010deni na va\u0161i napravi. Na za\u010detnem zaslonu je prikazan seznam vseh, z dotikom posameznega pa se izpi\u0161ejo: njegove zgo\u0161\u010dene vrednosti, podatki o podpisu in povezavi do informacij na virustotal.com ter androidobservatory.org. Poleg tega omogo\u010da \u0161e izvoz podpisnih potrdil in izdelavo ApkSignaturePin PIN datotek za uporabo s TrustedIntents knji\u017enico. \n\n\u2605 GOVORIMO VA\u0160 JEZIK: Checkey je na voljo za prijatelje, ki govorijo: Deutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk, portugu\u00eas (Portugal), \u0420\u0443\u0441\u0441\u043a\u0438\u0439, Sloven\u0161\u010dina, T\u00fcrk\u00e7e\nAli va\u0161 jezik ni na voljo? Pridru\u017eite se nam in nam pomagajte prevesti to aplikacijo:\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n***Izvedite ve\u010d***\n\u2605 O NAS: Guardian Project smo skupina razvijalcev, ki ustvarjamo varne in odprtokodne mobilne aplikacije za bolj\u0161i jutri\n\u2605 SPLETNA STRAN: https://GuardianProject.info\n\u2605 NA TWITTERJU: https://twitter.com/guardianproject\n\u2605 BREZPLA\u010cNO PROGRAMJE: Checkey je brezpla\u010den. Lahko si tudi ogledate njegovo izvorno kodo ali pa doprinesete k njegovemu razvoju, da bi postal \u0161e bolj\u0161i:\nhttps://gitlab.com/guardianproject/checkey\n\u2605 OBVESTITE NAS: Ali pogre\u0161ate kak\u0161no funkcionalnost? Ste na\u0161li hro\u0161\u010da? Veseli bomo va\u0161ega sporo\u010dila. Po\u0161ljite nam e-po\u0161to na: support@guardianproject.info ali nas poi\u0161\u010dite v na\u0161i klepetalnici na: https://guardianproject.info/contact\n", + "name": "Checkey: info o aplikacijah", + "summary": "orodje za pridobivanje informacij o APK paketih, ki so name\u0161\u010deni na va\u0161i napravi" + }, + "sv-SE": { + "summary": "verktyg f\u00f6r att f\u00e5 information om de APKs som \u00e4r installerade p\u00e5 din enhet\n" + }, + "sw": { + "summary": "shirika kwa ajili ya kupata taarifa kuhusu APK ambayo imewekwa kwenye kifaa chak" + }, + "th": { + "summary": "\u0e22\u0e39\u0e17\u0e34\u0e25\u0e34\u0e15\u0e35\u0e49\u0e2a\u0e33\u0e2b\u0e23\u0e31\u0e1a\u0e01\u0e32\u0e23\u0e23\u0e31\u0e1a\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e40\u0e01\u0e35\u0e48\u0e22\u0e27\u0e01\u0e31\u0e1a APKs \u0e17\u0e35\u0e48\u0e15\u0e34\u0e14\u0e15\u0e31\u0e49\u0e07\u0e2d\u0e22\u0e39\u0e48\u0e1a\u0e19\u0e2d\u0e38\u0e1b\u0e01\u0e23\u0e13\u0e4c\u0e02\u0e2d\u0e07\u0e04\u0e38\u0e13" + }, + "tr-TR": { + "description": "Checkey telefonunuzda y\u00fckl\u00fc olan APK'lar hakk\u0131nda bilgi sahibi olman\u0131za yarayan bir ara\u00e7t\u0131r. Telefonunuzda y\u00fckl\u00fc olan t\u00fcm uygulamalar\u0131 i\u00e7eren bir liste ile a\u00e7\u0131l\u0131r, size tek t\u0131klamayla APK imzas\u0131n\u0131 g\u00f6sterir bu APK'nun profillerine ula\u015fabilmeniz i\u00e7in virustotal.com ve androidobservatory.org adreslerine ba\u011flant\u0131lar sunar. Ayr\u0131ca TrustedIntents k\u00fct\u00fcphanesinde kullanabilmeniz i\u00e7in imzalama sertifikalar\u0131n\u0131 d\u0131\u015fa aktararak ApkSignaturePin pin dosyalar\u0131 olu\u015fturman\u0131za olanak sa\u011flar.\n\u2605 D\u0130L\u0130N\u0130Z\u0130 B\u0130L\u0130YORUZ: Checkey art\u0131k \u015fu dilleri bilen arkada\u015flar i\u00e7in haz\u0131r:\nDeutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk, portugu\u00eas (Portugal), \u0420\u0443\u0441\u0441\u043a\u0438\u0439, Sloven\u0161\u010dina, T\u00fcrk\u00e7e\nSizin diliniz yok mu? Bize kat\u0131l\u0131n ve \u00e7eviri i\u00e7in yard\u0131m edin:\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n***Daha Fazla***\n\u2605 HAKKIMIZDA: Guardian Project, daha iyi bir yar\u0131n i\u00e7in g\u00fcvenli mobil uygulamalar ve a\u00e7\u0131k-kaynak kodlar yazan bir geli\u015ftirici grubudur\n\u2605 WEB SAYFAMIZ: https://GuardianProject.info\n\u2605 TWITTER: https://twitter.com/guardianproject\n\u2605 \u00dcCRETS\u0130Z YAZILIM: Checkey \u00fccretsiz bir yaz\u0131l\u0131md\u0131r. Kaynak kodumuza bakabilir veya Checkey'i daha iyi yapabilmemiz i\u00e7in yard\u0131m edebilirsiniz:\nhttps://gitlab.com/guardianproject/checkey\n\u2605 B\u0130ZE YAZIN: En sevdi\u011finiz \u00f6zellikleri unutmu\u015f muyuz? Sinir bozucu bir hata m\u0131 ke\u015ffettiniz? L\u00fctfen bize bildirin! Bize support@guardianproject.info adresinden bir e-posta g\u00f6nderebilirsiniz veya bizi sohbet odam\u0131zda bulabilirsiniz: https://guardianproject.info/contact\n", + "name": "Checkey: yerel uyg. bilgileri\n", + "summary": "cihaz\u0131n\u0131zda y\u00fckl\u00fc olan APKlar hakk\u0131nda bilgi almaya yarayan bir ara\u00e7\n" + }, + "uk": { + "summary": "\u0443\u0442\u0438\u043b\u0456\u0442\u0430 \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u043c\u0430\u043d\u043d\u044f \u0456\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0456\u0457 \u043f\u0440\u043e APKs, \u0432\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0445 \u043d\u0430 \u0432\u0430\u0448\u043e\u043c\u0443 \u043f\u0440\u0438\u0441\u0442\u0440\u043e\u0457", + "whatsNew": "+ \u0432\u0456\u0434\u0442\u0432\u043e\u0440\u044e\u0432\u0430\u043d\u0456 \u0437\u0431\u0456\u0440\u043a\u0438\n+ \u0434\u043e\u0434\u0430\u043d\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434\u0438: fa fr zh-CN\n+ \u043e\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434\u0438: de pt_PT tr\n" + }, + "vi": { + "summary": "ti\u1ec7n \u00edch \u0111\u1ec3 nh\u1eadn th\u00f4ng tin v\u1ec1 c\u00e1c APK \u0111\u01b0\u1ee3c c\u00e0i \u0111\u1eb7t tr\u00ean thi\u1ebft b\u1ecb c\u1ee7a b\u1ea1n" + }, + "zh-CN": { + "description": "Checkey \u662f\u4e00\u4e2a\u83b7\u5f97\u5df2\u5b89\u88c5 APK \u76f8\u5173\u4fe1\u606f\u7684\u5b9e\u7528\u5de5\u5177\u3002\u5b83\u4ece\u60a8\u7684\u8bbe\u5907\u4e0a\u5df2\u5b89\u88c5\u7684\u6240\u6709\u5e94\u7528\u5f00\u59cb\uff0c\u4e00\u952e\u89e6\u6478\u5373\u53ef\u663e\u793a APK \u7684\u6307\u7eb9\uff0c\u5e76\u4e14\u63d0\u4f9b\u5230\u8fbe virustotal.com \u548c androidobservatory.org \u7684\u5feb\u6377\u94fe\u63a5\uff0c\u8ba9\u60a8\u65b9\u4fbf\u5730\u4e86\u89e3\u7279\u5b9a APK \u7684\u6863\u6848\u3002\u5b83\u8fd8\u53ef\u4ee5\u8ba9\u60a8\u5bfc\u51fa\u7b7e\u540d\u8bc1\u4e66\u548c\u751f\u6210 ApkSignaturePin Pin \u6587\u4ef6\u4f9b TrustedIntents \u5e93\u4f7f\u7528\u3002\n\u2605 Checkey \u652f\u6301\u4e0b\u5217\u8bed\u8a00\uff1a\nDeutsch, English, espa\u00f1ol, suomi, \u65e5\u672c\u8a9e, \ud55c\uad6d\uc5b4, Norsk, portugu\u00eas (Portugal), \u0420\u0443\u0441\u0441\u043a\u0438\u0439, Sloven\u0161\u010dina, T\u00fcrk\u00e7e\n\u6ca1\u770b\u5230\u60a8\u7684\u8bed\u8a00\uff1f\u5e2e\u5fd9\u7ffb\u8bd1\u672c\u5e94\u7528\u5427\uff1a\nhttps://hosted.weblate.org/projects/guardianproject/checkey/\nhttps://hosted.weblate.org/projects/guardianproject/checkey-metadata/\n\n***\u8be6\u7ec6\u4e86\u89e3***\n\u2605 \u5173\u4e8e\u6211\u4eec\uff1aGuardian \u9879\u76ee\u662f\u4e00\u4e2a\u5f00\u53d1\u8005\u5c0f\u7ec4\uff0c\u81f4\u529b\u4e8e\u521b\u9020\u79fb\u52a8\u5e94\u7528\u548c\u5f00\u6e90\u4ee3\u7801\u7684\u7f8e\u597d\u660e\u5929\n\u2605 \u6211\u4eec\u7684\u7f51\u7ad9: https://GuardianProject.info\n\u2605 \u6211\u4eec\u7684 Twitter: https://twitter.com/guardianproject\n\u2605 \u81ea\u7531\u8f6f\u4ef6\uff1aCheckey \u662f\u81ea\u7531\u8f6f\u4ef6\u3002\u60a8\u53ef\u4ee5\u67e5\u770b\u6211\u4eec\u7684\u6e90\u4ee3\u7801\uff0c\u8fd8\u53ef\u4ee5\u5e2e\u52a9\u6211\u4eec\u8ba9 Checkey \u53d8\u5f97\u66f4\u597d\uff1a\nhttps://gitlab.com/guardianproject/checkey\n\u2605 \u81f4\u7528\u6237\uff1a\u6211\u4eec\u8fd8\u7f3a\u5c11\u4f60\u559c\u6b22\u7684\u529f\u80fd\uff1f\u53d1\u73b0\u4e86\u4e00\u4e2a bug\uff1f\u8bf7\u544a\u8bc9\u6211\u4eec\uff01\u6211\u4eec\u4e50\u4e8e\u542c\u53d6\u60a8\u7684\u610f\u89c1\u3002\u8bf7\u53d1\u9001\u7535\u5b50\u90ae\u4ef6\u81f3: support@guardianproject.info \u6216\u8005\u52a0\u5165\u6211\u4eec\u7684\u804a\u5929\u5ba4 https://guardianproject.info/contact\n", + "name": "Checkey\uff1a\u672c\u5730\u5e94\u7528\u7684\u4fe1\u606f\n", + "summary": "\u4e00\u4e2a\u5b9e\u7528\u5de5\u5177\uff0c\u83b7\u53d6\u5df2\u5b89\u88c5\u5728\u60a8\u7684\u8bbe\u5907\u4e0a\u7684\u5e94\u7528\u7684\u6709\u5173\u4fe1\u606f\n" + } + } + } + ], + "packages": { + "info.guardianproject.checkey": [ + { + "added": 1425859200000, + "apkName": "Checkey-0.1.2.apk", + "hash": "754701dbac52de5ca3930c2393970c03ef9aa07d1456911e9bf254d6014e0645", + "hashType": "sha256", + "minSdkVersion": 8, + "packageName": "info.guardianproject.checkey", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "signer": "f006a20481c71a690de02e385ab0c9fa4ac1245240f68102682703ba0656867a", + "size": 842881, + "targetSdkVersion": 21, + "uses-permission": [ + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 102, + "versionName": "0.1.2" + }, + { + "added": 1422403200000, + "apkName": "Checkey-0.1.1.apk", + "hash": "2d81f339bb69626af42e8868dc6928c9072ebcbae76e1ff5ac8172e78ebe9cdd", + "hashType": "sha256", + "minSdkVersion": 8, + "packageName": "info.guardianproject.checkey", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "signer": "f006a20481c71a690de02e385ab0c9fa4ac1245240f68102682703ba0656867a", + "size": 967083, + "targetSdkVersion": 21, + "uses-permission": [ + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 101, + "versionName": "0.1.1" + }, + { + "added": 1405123200000, + "apkName": "Checkey-0.1.apk", + "hash": "a8e3c102d5279a3029d0eebdeda2ffdbe1f8a3493ea7dbdc31a11affc708ee57", + "hashType": "sha256", + "minSdkVersion": 8, + "packageName": "info.guardianproject.checkey", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "signer": "f006a20481c71a690de02e385ab0c9fa4ac1245240f68102682703ba0656867a", + "size": 878679, + "targetSdkVersion": 19, + "uses-permission": [ + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 1, + "versionName": "0.1" + } + ] + } +}