Merge branch 'main' into added-button

This commit is contained in:
Nishthajain7 2025-07-11 17:58:10 +05:30 committed by GitHub
commit 5c05e7d0f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
137 changed files with 1920 additions and 1420 deletions

View file

@ -1,7 +1,7 @@
name: "\U0001F41E Bug report" name: "\U0001F41E Bug report"
description: Create a report to help us improve. description: Create a report to help us improve.
title: "[Bug]: " title: "[Bug]: "
labels: ["bug"] type: Bug # Retained to categorize the issue as per organization-level type
body: body:
- type: markdown - type: markdown
attributes: attributes:

View file

@ -16,6 +16,7 @@
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" /> <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
<option name="IMPORT_LAYOUT_TABLE"> <option name="IMPORT_LAYOUT_TABLE">
<value> <value>
<package name="" withSubpackages="true" static="false" module="true" />
<package name="" withSubpackages="true" static="true" /> <package name="" withSubpackages="true" static="true" />
<emptyLine /> <emptyLine />
<package name="" withSubpackages="true" static="false" /> <package name="" withSubpackages="true" static="false" />

View file

@ -1,5 +1,15 @@
# Wikimedia Commons for Android # Wikimedia Commons for Android
## v5.5.0
### What's changed
* Explore images will now be shown based on the map location and not at your current location
* Enhanced Wikidata feedback message
* Green labels in Explore map will no longer be hidden by other pins thumbnails
* Upload wizard's language drop-down now reflects the language used in the pin label
* Users can now pick only one image at a time while using the custom selector
* Bug fixes and stability improvements
## v5.4.1 ## v5.4.1
### What's changed ### What's changed

View file

@ -24,8 +24,8 @@ android {
applicationId = "fr.free.nrw.commons" applicationId = "fr.free.nrw.commons"
minSdk = 21 minSdk = 21
targetSdk = 34 targetSdk = 34
versionCode = 1052 versionCode = 1053
versionName = "5.4.1" versionName = "5.5.0"
setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName()) setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName())
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@ -347,6 +347,7 @@ dependencies {
// Kotlin + coroutines // Kotlin + coroutines
implementation(libs.androidx.work.runtime.ktx) implementation(libs.androidx.work.runtime.ktx)
implementation(libs.androidx.work.runtime) implementation(libs.androidx.work.runtime)
implementation(libs.kotlinx.coroutines.rx2)
testImplementation(libs.androidx.work.testing) testImplementation(libs.androidx.work.testing)
//Glide //Glide

View file

@ -66,6 +66,9 @@
# Application classes that will be serialized/deserialized over Gson # Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; } -keep class com.google.gson.examples.android.model.** { *; }
# Prevent R8 from obfuscating project classes used by Gson for parsing
-keep class fr.free.nrw.commons.fileusages.** { *; }
# Prevent proguard from stripping interface information from TypeAdapterFactory, # Prevent proguard from stripping interface information from TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * implements com.google.gson.TypeAdapterFactory -keep class * implements com.google.gson.TypeAdapterFactory

View file

@ -1,7 +1,9 @@
package fr.free.nrw.commons package fr.free.nrw.commons
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.content.Intent.ACTION_VIEW
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
@ -16,6 +18,9 @@ import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
import java.util.Collections import java.util.Collections
import androidx.core.net.toUri
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.utils.setUnderlinedText
/** /**
* Represents about screen of this app * Represents about screen of this app
@ -59,30 +64,12 @@ class AboutActivity : BaseActivity() {
binding!!.aboutImprove.setHtmlText(improveText) binding!!.aboutImprove.setHtmlText(improveText)
binding!!.aboutVersion.text = applicationContext.getVersionNameWithSha() binding!!.aboutVersion.text = applicationContext.getVersionNameWithSha()
Utils.setUnderlinedText( binding!!.aboutFaq.setUnderlinedText(R.string.about_faq)
binding!!.aboutFaq, R.string.about_faq, binding!!.aboutRateUs.setUnderlinedText(R.string.about_rate_us)
applicationContext binding!!.aboutUserGuide.setUnderlinedText(R.string.user_guide)
) binding!!.aboutPrivacyPolicy.setUnderlinedText(R.string.about_privacy_policy)
Utils.setUnderlinedText( binding!!.aboutTranslate.setUnderlinedText(R.string.about_translate)
binding!!.aboutRateUs, R.string.about_rate_us, binding!!.aboutCredits.setUnderlinedText(R.string.about_credits)
applicationContext
)
Utils.setUnderlinedText(
binding!!.aboutUserGuide, R.string.user_guide,
applicationContext
)
Utils.setUnderlinedText(
binding!!.aboutPrivacyPolicy, R.string.about_privacy_policy,
applicationContext
)
Utils.setUnderlinedText(
binding!!.aboutTranslate, R.string.about_translate,
applicationContext
)
Utils.setUnderlinedText(
binding!!.aboutCredits, R.string.about_credits,
applicationContext
)
/* /*
To set listeners, we can create a separate method and use lambda syntax. To set listeners, we can create a separate method and use lambda syntax.
@ -106,47 +93,56 @@ class AboutActivity : BaseActivity() {
fun launchFacebook(view: View?) { fun launchFacebook(view: View?) {
val intent: Intent val intent: Intent
try { try {
intent = Intent(Intent.ACTION_VIEW, Uri.parse(Urls.FACEBOOK_APP_URL)) intent = Intent(ACTION_VIEW, Urls.FACEBOOK_APP_URL.toUri())
intent.setPackage(Urls.FACEBOOK_PACKAGE_NAME) intent.setPackage(Urls.FACEBOOK_PACKAGE_NAME)
startActivity(intent) startActivity(intent)
} catch (e: Exception) { } catch (e: Exception) {
Utils.handleWebUrl(this, Uri.parse(Urls.FACEBOOK_WEB_URL)) handleWebUrl(this, Urls.FACEBOOK_WEB_URL.toUri())
} }
} }
fun launchGithub(view: View?) { fun launchGithub(view: View?) {
val intent: Intent val intent: Intent
try { try {
intent = Intent(Intent.ACTION_VIEW, Uri.parse(Urls.GITHUB_REPO_URL)) intent = Intent(ACTION_VIEW, Urls.GITHUB_REPO_URL.toUri())
intent.setPackage(Urls.GITHUB_PACKAGE_NAME) intent.setPackage(Urls.GITHUB_PACKAGE_NAME)
startActivity(intent) startActivity(intent)
} catch (e: Exception) { } catch (e: Exception) {
Utils.handleWebUrl(this, Uri.parse(Urls.GITHUB_REPO_URL)) handleWebUrl(this, Urls.GITHUB_REPO_URL.toUri())
} }
} }
fun launchWebsite(view: View?) { fun launchWebsite(view: View?) {
Utils.handleWebUrl(this, Uri.parse(Urls.WEBSITE_URL)) handleWebUrl(this, Urls.WEBSITE_URL.toUri())
} }
fun launchRatings(view: View?) { fun launchRatings(view: View?) {
Utils.rateApp(this) try {
startActivity(
Intent(
ACTION_VIEW,
(Urls.PLAY_STORE_PREFIX + packageName).toUri()
)
)
} catch (_: ActivityNotFoundException) {
handleWebUrl(this, (Urls.PLAY_STORE_URL_PREFIX + packageName).toUri())
}
} }
fun launchCredits(view: View?) { fun launchCredits(view: View?) {
Utils.handleWebUrl(this, Uri.parse(Urls.CREDITS_URL)) handleWebUrl(this, Urls.CREDITS_URL.toUri())
} }
fun launchUserGuide(view: View?) { fun launchUserGuide(view: View?) {
Utils.handleWebUrl(this, Uri.parse(Urls.USER_GUIDE_URL)) handleWebUrl(this, Urls.USER_GUIDE_URL.toUri())
} }
fun launchPrivacyPolicy(view: View?) { fun launchPrivacyPolicy(view: View?) {
Utils.handleWebUrl(this, Uri.parse(BuildConfig.PRIVACY_POLICY_URL)) handleWebUrl(this, BuildConfig.PRIVACY_POLICY_URL.toUri())
} }
fun launchFrequentlyAskedQuesions(view: View?) { fun launchFrequentlyAskedQuesions(view: View?) {
Utils.handleWebUrl(this, Uri.parse(Urls.FAQ_URL)) handleWebUrl(this, Urls.FAQ_URL.toUri())
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
@ -193,7 +189,7 @@ class AboutActivity : BaseActivity() {
val positiveButtonRunnable = Runnable { val positiveButtonRunnable = Runnable {
val langCode = instance.languageLookUpTable!!.getCodes()[spinner.selectedItemPosition] val langCode = instance.languageLookUpTable!!.getCodes()[spinner.selectedItemPosition]
Utils.handleWebUrl(this@AboutActivity, Uri.parse(Urls.TRANSLATE_WIKI_URL + langCode)) handleWebUrl(this@AboutActivity, (Urls.TRANSLATE_WIKI_URL + langCode).toUri())
} }
showAlertDialog( showAlertDialog(
this, this,

View file

@ -1,18 +0,0 @@
package fr.free.nrw.commons;
import androidx.annotation.NonNull;
/**
* Base presenter, enforcing contracts to atach and detach view
*/
public interface BasePresenter<T> {
/**
* Until a view is attached, it is open to listen events from the presenter
*/
void onAttachView(@NonNull T view);
/**
* Detaching a view makes sure that the view no more receives events from the presenter
*/
void onDetachView();
}

View file

@ -0,0 +1,10 @@
package fr.free.nrw.commons
/**
* Base presenter, enforcing contracts to attach and detach view
*/
interface BasePresenter<T> {
fun onAttachView(view: T)
fun onDetachView()
}

View file

@ -1,79 +0,0 @@
package fr.free.nrw.commons;
import androidx.annotation.Nullable;
/**
* represents Licence object
*/
public class License {
private String key;
private String template;
private String url;
private String name;
/**
* Constructs a new instance of License.
*
* @param key license key
* @param template license template
* @param url license URL
* @param name licence name
*
* @throws RuntimeException if License.key or Licence.template is null
*/
public License(String key, String template, String url, String name) {
if (key == null) {
throw new RuntimeException("License.key must not be null");
}
if (template == null) {
throw new RuntimeException("License.template must not be null");
}
this.key = key;
this.template = template;
this.url = url;
this.name = name;
}
/**
* Gets the license key.
* @return license key as a String.
*/
public String getKey() {
return key;
}
/**
* Gets the license template.
* @return license template as a String.
*/
public String getTemplate() {
return template;
}
/**
* Gets the license name. If name is null, return license key.
* @return license name as string. if name null, license key as String
*/
public String getName() {
if (name == null) {
// hack
return getKey();
} else {
return name;
}
}
/**
* Gets the license URL
*
* @param language license language
* @return URL
*/
public @Nullable String getUrl(String language) {
if (url == null) {
return null;
} else {
return url.replace("$lang", language);
}
}
}

View file

@ -1,30 +0,0 @@
package fr.free.nrw.commons;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.nearby.Place;
import java.util.List;
public abstract class MapController {
/**
* We pass this variable as a group of placeList and boundaryCoordinates
*/
public class NearbyPlacesInfo {
public List<Place> placeList; // List of nearby places
public LatLng[] boundaryCoordinates; // Corners of nearby area
public LatLng currentLatLng; // Current location when this places are populated
public LatLng searchLatLng; // Search location for finding this places
public List<Media> mediaList; // Search location for finding this places
}
/**
* We pass this variable as a group of placeList and boundaryCoordinates
*/
public class ExplorePlacesInfo {
public List<Place> explorePlaceList; // List of nearby places
public LatLng[] boundaryCoordinates; // Corners of nearby area
public LatLng currentLatLng; // Current location when this places are populated
public LatLng searchLatLng; // Search location for finding this places
public List<Media> mediaList; // Search location for finding this places
}
}

View file

@ -0,0 +1,46 @@
package fr.free.nrw.commons
import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.nearby.Place
abstract class MapController {
/**
* We pass this variable as a group of placeList and boundaryCoordinates
*/
inner class NearbyPlacesInfo {
@JvmField
var placeList: List<Place> = emptyList() // List of nearby places
@JvmField
var boundaryCoordinates: Array<LatLng> = emptyArray() // Corners of nearby area
@JvmField
var currentLatLng: LatLng? = null // Current location when this places are populated
@JvmField
var searchLatLng: LatLng? = null // Search location for finding this places
@JvmField
var mediaList: List<Media>? = null // Search location for finding this places
}
/**
* We pass this variable as a group of placeList and boundaryCoordinates
*/
inner class ExplorePlacesInfo {
@JvmField
var explorePlaceList: List<Place> = emptyList() // List of nearby places
@JvmField
var boundaryCoordinates: Array<LatLng> = emptyArray() // Corners of nearby area
@JvmField
var currentLatLng: LatLng? = null // Current location when this places are populated
@JvmField
var searchLatLng: LatLng? = null // Search location for finding this places
@JvmField
var mediaList: List<Media> = emptyList() // Search location for finding this places
}
}

View file

@ -1,7 +1,9 @@
package fr.free.nrw.commons package fr.free.nrw.commons
import android.os.Parcelable import android.os.Parcelable
import fr.free.nrw.commons.BuildConfig.COMMONS_URL
import fr.free.nrw.commons.location.LatLng import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.wikidata.model.WikiSite
import fr.free.nrw.commons.wikidata.model.page.PageTitle import fr.free.nrw.commons.wikidata.model.page.PageTitle
import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@ -173,7 +175,8 @@ class Media constructor(
* Gets file page title * Gets file page title
* @return New media page title * @return New media page title
*/ */
val pageTitle: PageTitle get() = Utils.getPageTitle(filename!!) val pageTitle: PageTitle
get() = PageTitle(filename!!, WikiSite(COMMONS_URL))
/** /**
* Returns wikicode to use the media file on a MediaWiki site * Returns wikicode to use the media file on a MediaWiki site

View file

@ -1,8 +0,0 @@
package fr.free.nrw.commons;
/**
* Base interface for all the views
*/
public interface MvpView {
void showMessage(String message);
}

View file

@ -1,154 +0,0 @@
package fr.free.nrw.commons;
import androidx.annotation.NonNull;
import fr.free.nrw.commons.wikidata.cookies.CommonsCookieJar;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import okhttp3.Cache;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.logging.HttpLoggingInterceptor;
import okhttp3.logging.HttpLoggingInterceptor.Level;
import timber.log.Timber;
public final class OkHttpConnectionFactory {
private static final String CACHE_DIR_NAME = "okhttp-cache";
private static final long NET_CACHE_SIZE = 64 * 1024 * 1024;
public static OkHttpClient CLIENT;
@NonNull public static OkHttpClient getClient(final CommonsCookieJar cookieJar) {
if (CLIENT == null) {
CLIENT = createClient(cookieJar);
}
return CLIENT;
}
@NonNull
private static OkHttpClient createClient(final CommonsCookieJar cookieJar) {
return new OkHttpClient.Builder()
.cookieJar(cookieJar)
.cache((CommonsApplication.getInstance()!=null) ? new Cache(new File(CommonsApplication.getInstance().getCacheDir(), CACHE_DIR_NAME), NET_CACHE_SIZE) : null)
.connectTimeout(120, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.addInterceptor(getLoggingInterceptor())
.addInterceptor(new UnsuccessfulResponseInterceptor())
.addInterceptor(new CommonHeaderRequestInterceptor())
.build();
}
private static HttpLoggingInterceptor getLoggingInterceptor() {
final HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor()
.setLevel(Level.BASIC);
httpLoggingInterceptor.redactHeader("Authorization");
httpLoggingInterceptor.redactHeader("Cookie");
return httpLoggingInterceptor;
}
private static class CommonHeaderRequestInterceptor implements Interceptor {
@Override
@NonNull
public Response intercept(@NonNull final Chain chain) throws IOException {
final Request request = chain.request().newBuilder()
.header("User-Agent", CommonsApplication.getInstance().getUserAgent())
.build();
return chain.proceed(request);
}
}
public static class UnsuccessfulResponseInterceptor implements Interceptor {
private static final String SUPPRESS_ERROR_LOG = "x-commons-suppress-error-log";
public static final String SUPPRESS_ERROR_LOG_HEADER = SUPPRESS_ERROR_LOG+": true";
private static final List<String> DO_NOT_INTERCEPT = Collections.singletonList(
"api.php?format=json&formatversion=2&errorformat=plaintext&action=upload&ignorewarnings=1");
private static final String ERRORS_PREFIX = "{\"error";
@Override
@NonNull
public Response intercept(@NonNull final Chain chain) throws IOException {
final Request rq = chain.request();
// If the request contains our special "suppress errors" header, make note of it
// but don't pass that on to the server.
final boolean suppressErrors = rq.headers().names().contains(SUPPRESS_ERROR_LOG);
final Request request = rq.newBuilder()
.removeHeader(SUPPRESS_ERROR_LOG)
.build();
final Response rsp = chain.proceed(request);
// Do not intercept certain requests and let the caller handle the errors
if(isExcludedUrl(chain.request())) {
return rsp;
}
if (rsp.isSuccessful()) {
try (final ResponseBody responseBody = rsp.peekBody(ERRORS_PREFIX.length())) {
if (ERRORS_PREFIX.equals(responseBody.string())) {
try (final ResponseBody body = rsp.body()) {
throw new IOException(body.string());
}
}
} catch (final IOException e) {
// Log the error as debug (and therefore, "expected") or at error level
if (suppressErrors) {
Timber.d(e, "Suppressed (known / expected) error");
} else {
Timber.e(e);
}
}
return rsp;
}
throw new HttpStatusException(rsp);
}
private boolean isExcludedUrl(final Request request) {
final String requestUrl = request.url().toString();
for(final String url: DO_NOT_INTERCEPT) {
if(requestUrl.contains(url)) {
return true;
}
}
return false;
}
}
private OkHttpConnectionFactory() {
}
public static class HttpStatusException extends IOException {
private final int code;
private final String url;
public HttpStatusException(@NonNull Response rsp) {
this.code = rsp.code();
this.url = rsp.request().url().uri().toString();
try {
if (rsp.body() != null && rsp.body().contentType() != null
&& rsp.body().contentType().toString().contains("json")) {
}
} catch (Exception e) {
// Log?
}
}
public int code() {
return code;
}
@Override
public String getMessage() {
String str = "Code: " + code + ", URL: " + url;
return str;
}
}
}

View file

@ -0,0 +1,122 @@
package fr.free.nrw.commons
import androidx.annotation.VisibleForTesting
import fr.free.nrw.commons.wikidata.cookies.CommonsCookieJar
import okhttp3.Cache
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import timber.log.Timber
import java.io.File
import java.io.IOException
import java.util.concurrent.TimeUnit
object OkHttpConnectionFactory {
private const val CACHE_DIR_NAME = "okhttp-cache"
private const val NET_CACHE_SIZE = (64 * 1024 * 1024).toLong()
@VisibleForTesting
var CLIENT: OkHttpClient? = null
fun getClient(cookieJar: CommonsCookieJar): OkHttpClient {
if (CLIENT == null) {
CLIENT = createClient(cookieJar)
}
return CLIENT!!
}
private fun createClient(cookieJar: CommonsCookieJar): OkHttpClient {
return OkHttpClient.Builder()
.cookieJar(cookieJar)
.cache(
if (CommonsApplication.instance != null) Cache(
File(CommonsApplication.instance.cacheDir, CACHE_DIR_NAME),
NET_CACHE_SIZE
) else null
)
.connectTimeout(120, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.readTimeout(120, TimeUnit.SECONDS)
.addInterceptor(HttpLoggingInterceptor().apply {
setLevel(HttpLoggingInterceptor.Level.BASIC)
redactHeader("Authorization")
redactHeader("Cookie")
})
.addInterceptor(UnsuccessfulResponseInterceptor())
.addInterceptor(CommonHeaderRequestInterceptor())
.build()
}
}
private class CommonHeaderRequestInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.header("User-Agent", CommonsApplication.instance.userAgent)
.build()
return chain.proceed(request)
}
}
private const val SUPPRESS_ERROR_LOG = "x-commons-suppress-error-log"
const val SUPPRESS_ERROR_LOG_HEADER: String = "$SUPPRESS_ERROR_LOG: true"
private class UnsuccessfulResponseInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val rq = chain.request()
// If the request contains our special "suppress errors" header, make note of it
// but don't pass that on to the server.
val suppressErrors = rq.headers.names().contains(SUPPRESS_ERROR_LOG)
val request = rq.newBuilder()
.removeHeader(SUPPRESS_ERROR_LOG)
.build()
val rsp = chain.proceed(request)
// Do not intercept certain requests and let the caller handle the errors
if (isExcludedUrl(chain.request())) {
return rsp
}
if (rsp.isSuccessful) {
try {
rsp.peekBody(ERRORS_PREFIX.length.toLong()).use { responseBody ->
if (ERRORS_PREFIX == responseBody.string()) {
rsp.body.use { body ->
throw IOException(body!!.string())
}
}
}
} catch (e: IOException) {
// Log the error as debug (and therefore, "expected") or at error level
if (suppressErrors) {
Timber.d(e, "Suppressed (known / expected) error")
} else {
Timber.e(e)
}
}
return rsp
}
throw IOException("Unsuccessful response")
}
private fun isExcludedUrl(request: Request): Boolean {
val requestUrl = request.url.toString()
for (url in DO_NOT_INTERCEPT) {
if (requestUrl.contains(url)) {
return true
}
}
return false
}
companion object {
val DO_NOT_INTERCEPT = listOf(
"api.php?format=json&formatversion=2&errorformat=plaintext&action=upload&ignorewarnings=1"
)
const val ERRORS_PREFIX = "{\"error"
}
}

View file

@ -1,264 +0,0 @@
package fr.free.nrw.commons;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.text.SpannableString;
import android.text.style.UnderlineSpan;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.browser.customtabs.CustomTabColorSchemeParams;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.core.content.ContextCompat;
import java.util.Calendar;
import java.util.Date;
import fr.free.nrw.commons.wikidata.model.WikiSite;
import fr.free.nrw.commons.wikidata.model.page.PageTitle;
import java.util.Locale;
import java.util.regex.Pattern;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.settings.Prefs;
import fr.free.nrw.commons.utils.ViewUtil;
import timber.log.Timber;
public class Utils {
public static PageTitle getPageTitle(@NonNull String title) {
return new PageTitle(title, new WikiSite(BuildConfig.COMMONS_URL));
}
/**
* Generates licence name with given ID
* @param license License ID
* @return Name of license
*/
public static int licenseNameFor(String license) {
switch (license) {
case Prefs.Licenses.CC_BY_3:
return R.string.license_name_cc_by;
case Prefs.Licenses.CC_BY_4:
return R.string.license_name_cc_by_four;
case Prefs.Licenses.CC_BY_SA_3:
return R.string.license_name_cc_by_sa;
case Prefs.Licenses.CC_BY_SA_4:
return R.string.license_name_cc_by_sa_four;
case Prefs.Licenses.CC0:
return R.string.license_name_cc0;
}
throw new IllegalStateException("Unrecognized license value: " + license);
}
/**
* Generates license url with given ID
* @param license License ID
* @return Url of license
*/
@NonNull
public static String licenseUrlFor(String license) {
switch (license) {
case Prefs.Licenses.CC_BY_3:
return "https://creativecommons.org/licenses/by/3.0/";
case Prefs.Licenses.CC_BY_4:
return "https://creativecommons.org/licenses/by/4.0/";
case Prefs.Licenses.CC_BY_SA_3:
return "https://creativecommons.org/licenses/by-sa/3.0/";
case Prefs.Licenses.CC_BY_SA_4:
return "https://creativecommons.org/licenses/by-sa/4.0/";
case Prefs.Licenses.CC0:
return "https://creativecommons.org/publicdomain/zero/1.0/";
default:
throw new IllegalStateException("Unrecognized license value: " + license);
}
}
/**
* Adds extension to filename. Converts to .jpg if system provides .jpeg, adds .jpg if no extension detected
* @param title File name
* @param extension Correct extension
* @return File with correct extension
*/
public static String fixExtension(String title, String extension) {
Pattern jpegPattern = Pattern.compile("\\.jpeg$", Pattern.CASE_INSENSITIVE);
// People are used to ".jpg" more than ".jpeg" which the system gives us.
if (extension != null && extension.toLowerCase(Locale.ENGLISH).equals("jpeg")) {
extension = "jpg";
}
title = jpegPattern.matcher(title).replaceFirst(".jpg");
if (extension != null && !title.toLowerCase(Locale.getDefault())
.endsWith("." + extension.toLowerCase(Locale.ENGLISH))) {
title += "." + extension;
}
// If extension is still null, make it jpg. (Hotfix for https://github.com/commons-app/apps-android-commons/issues/228)
// If title has an extension in it, if won't be true
if (extension == null && title.lastIndexOf(".")<=0) {
extension = "jpg";
title += "." + extension;
}
return title;
}
/**
* Launches intent to rate app
* @param context
*/
public static void rateApp(Context context) {
final String appPackageName = context.getPackageName();
try {
context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Urls.PLAY_STORE_PREFIX + appPackageName)));
}
catch (android.content.ActivityNotFoundException anfe) {
handleWebUrl(context, Uri.parse(Urls.PLAY_STORE_URL_PREFIX + appPackageName));
}
}
/**
* Opens Custom Tab Activity with in-app browser for the specified URL.
* Launches intent for web URL
* @param context
* @param url
*/
public static void handleWebUrl(Context context, Uri url) {
Timber.d("Launching web url %s", url.toString());
final CustomTabColorSchemeParams color = new CustomTabColorSchemeParams.Builder()
.setToolbarColor(ContextCompat.getColor(context, R.color.primaryColor))
.setSecondaryToolbarColor(ContextCompat.getColor(context, R.color.primaryDarkColor))
.build();
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
builder.setDefaultColorSchemeParams(color);
builder.setExitAnimations(context, android.R.anim.slide_in_left, android.R.anim.slide_out_right);
CustomTabsIntent customTabsIntent = builder.build();
// Clear previous browser tasks, so that back/exit buttons work as intended.
customTabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
customTabsIntent.launchUrl(context, url);
}
/**
* Util function to handle geo coordinates. It no longer depends on google maps and any app
* capable of handling the map intent can handle it
*
* @param context The context for launching intent
* @param latLng The latitude and longitude of the location
*/
public static void handleGeoCoordinates(final Context context, final LatLng latLng) {
handleGeoCoordinates(context, latLng, 16);
}
/**
* Util function to handle geo coordinates with specified zoom level. It no longer depends on
* google maps and any app capable of handling the map intent can handle it
*
* @param context The context for launching intent
* @param latLng The latitude and longitude of the location
* @param zoomLevel The zoom level
*/
public static void handleGeoCoordinates(final Context context, final LatLng latLng,
final double zoomLevel) {
final Intent mapIntent = new Intent(Intent.ACTION_VIEW, latLng.getGmmIntentUri(zoomLevel));
if (mapIntent.resolveActivity(context.getPackageManager()) != null) {
context.startActivity(mapIntent);
} else {
ViewUtil.showShortToast(context, context.getString(R.string.map_application_missing));
}
}
/**
* To take screenshot of the screen and return it in Bitmap format
*
* @param view
* @return
*/
public static Bitmap getScreenShot(View view) {
View screenView = view.getRootView();
screenView.setDrawingCacheEnabled(true);
Bitmap drawingCache = screenView.getDrawingCache();
if (drawingCache != null) {
Bitmap bitmap = Bitmap.createBitmap(drawingCache);
screenView.setDrawingCacheEnabled(false);
return bitmap;
}
return null;
}
/*
*Copies the content to the clipboard
*
*/
public static void copy(String label,String text, Context context){
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText(label, text);
clipboard.setPrimaryClip(clip);
}
/**
* This method sets underlined string text to a TextView
*
* @param textView TextView associated with string resource
* @param stringResourceName string resource name
* @param context
*/
public static void setUnderlinedText(TextView textView, int stringResourceName, Context context) {
SpannableString content = new SpannableString(context.getString(stringResourceName));
content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
textView.setText(content);
}
/**
* For now we are enabling the monuments only when the date lies between 1 Sept & 31 OCt
* @param date
* @return
*/
public static boolean isMonumentsEnabled(final Date date) {
if (date.getMonth() == 8) {
return true;
}
return false;
}
/**
* Util function to get the start date of wlm monument
* For this release we are hardcoding it to be 1st September
* @return
*/
public static String getWLMStartDate() {
return "1 Sep";
}
/***
* Util function to get the end date of wlm monument
* For this release we are hardcoding it to be 31st October
* @return
*/
public static String getWLMEndDate() {
return "30 Sep";
}
/***
* Function to get the current WLM year
* It increments at the start of September in line with the other WLM functions
* (No consideration of locales for now)
* @param calendar
* @return
*/
public static int getWikiLovesMonumentsYear(Calendar calendar) {
int year = calendar.get(Calendar.YEAR);
if (calendar.get(Calendar.MONTH) < Calendar.SEPTEMBER) {
year -= 1;
}
return year;
}
}

View file

@ -1,7 +0,0 @@
package fr.free.nrw.commons;
import android.content.Context;
public interface ViewHolder<T> {
void bindModel(Context context, T model);
}

View file

@ -1,68 +0,0 @@
package fr.free.nrw.commons;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import java.util.ArrayList;
import java.util.List;
/**
* This adapter will be used to display fragments in a ViewPager
*/
public class ViewPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragmentList = new ArrayList<>();
private List<String> fragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
/**
* Constructs a ViewPagerAdapter with a specified Fragment Manager and Fragment resume behavior.
*
* @param manager The FragmentManager
* @param behavior An integer which represents the behavior of non visible fragments. See
* FragmentPagerAdapter.java for options.
*/
public ViewPagerAdapter(FragmentManager manager, int behavior) {
super(manager, behavior);
}
/**
* This method returns the fragment of the viewpager at a particular position
* @param position
*/
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
/**
* This method returns the total number of fragments in the viewpager.
* @return size
*/
@Override
public int getCount() {
return fragmentList.size();
}
/**
* This method sets the fragment and title list in the viewpager
* @param fragmentList List of all fragments to be displayed in the viewpager
* @param fragmentTitleList List of all titles of the fragments
*/
public void setTabData(List<Fragment> fragmentList, List<String> fragmentTitleList) {
this.fragmentList = fragmentList;
this.fragmentTitleList = fragmentTitleList;
}
/**
* This method returns the title of the page at a particular position
* @param position
*/
@Override
public CharSequence getPageTitle(int position) {
return fragmentTitleList.get(position);
}
}

View file

@ -0,0 +1,44 @@
package fr.free.nrw.commons
import android.content.Context
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentPagerAdapter
import java.util.Locale
/**
* This adapter will be used to display fragments in a ViewPager
*/
class ViewPagerAdapter : FragmentPagerAdapter {
private val context: Context
private var fragmentList: List<Fragment> = emptyList()
private var fragmentTitleList: List<String> = emptyList()
constructor(context: Context, manager: FragmentManager) : super(manager) {
this.context = context
}
constructor(context: Context, manager: FragmentManager, behavior: Int) : super(manager, behavior) {
this.context = context
}
override fun getItem(position: Int): Fragment = fragmentList[position]
override fun getPageTitle(position: Int): CharSequence = fragmentTitleList[position]
override fun getCount(): Int = fragmentList.size
fun setTabs(vararg titlesToFragments: Pair<Int, Fragment>) {
// Enforce that every title must come from strings.xml and all will consistently be uppercase
fragmentTitleList = titlesToFragments.map {
context.getString(it.first).uppercase(Locale.ROOT)
}
fragmentList = titlesToFragments.map { it.second }
}
companion object {
// Convenience method for Java callers, can be removed when everything is migrated
@JvmStatic
fun pairOf(first: Int, second: Fragment) = first to second
}
}

View file

@ -1,109 +0,0 @@
package fr.free.nrw.commons;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import fr.free.nrw.commons.databinding.ActivityWelcomeBinding;
import fr.free.nrw.commons.databinding.PopupForCopyrightBinding;
import fr.free.nrw.commons.quiz.QuizActivity;
import fr.free.nrw.commons.theme.BaseActivity;
import fr.free.nrw.commons.utils.ConfigUtils;
public class WelcomeActivity extends BaseActivity {
private ActivityWelcomeBinding binding;
private PopupForCopyrightBinding copyrightBinding;
private final WelcomePagerAdapter adapter = new WelcomePagerAdapter();
private boolean isQuiz;
private AlertDialog.Builder dialogBuilder;
private AlertDialog dialog;
/**
* Initialises exiting fields and dependencies
*
* @param savedInstanceState WelcomeActivity bundled data
*/
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityWelcomeBinding.inflate(getLayoutInflater());
final View view = binding.getRoot();
setContentView(view);
if (getIntent() != null) {
final Bundle bundle = getIntent().getExtras();
if (bundle != null) {
isQuiz = bundle.getBoolean("isQuiz");
}
} else {
isQuiz = false;
}
// Enable skip button if beta flavor
if (ConfigUtils.isBetaFlavour()) {
binding.finishTutorialButton.setVisibility(View.VISIBLE);
dialogBuilder = new AlertDialog.Builder(this);
copyrightBinding = PopupForCopyrightBinding.inflate(getLayoutInflater());
final View contactPopupView = copyrightBinding.getRoot();
dialogBuilder.setView(contactPopupView);
dialogBuilder.setCancelable(false);
dialog = dialogBuilder.create();
dialog.show();
copyrightBinding.buttonOk.setOnClickListener(v -> dialog.dismiss());
}
binding.welcomePager.setAdapter(adapter);
binding.welcomePagerIndicator.setViewPager(binding.welcomePager);
binding.finishTutorialButton.setOnClickListener(v -> finishTutorial());
}
/**
* References WelcomePageAdapter to null before the activity is destroyed
*/
@Override
public void onDestroy() {
if (isQuiz) {
final Intent i = new Intent(this, QuizActivity.class);
startActivity(i);
}
super.onDestroy();
}
/**
* Creates a way to change current activity to WelcomeActivity
*
* @param context Activity context
*/
public static void startYourself(final Context context) {
final Intent welcomeIntent = new Intent(context, WelcomeActivity.class);
context.startActivity(welcomeIntent);
}
/**
* Override onBackPressed() to go to previous tutorial 'pages' if not on first page
*/
@Override
public void onBackPressed() {
if (binding.welcomePager.getCurrentItem() != 0) {
binding.welcomePager.setCurrentItem(binding.welcomePager.getCurrentItem() - 1, true);
} else {
if (defaultKvStore.getBoolean("firstrun", true)) {
finishAffinity();
} else {
super.onBackPressed();
}
}
}
public void finishTutorial() {
defaultKvStore.putBoolean("firstrun", false);
finish();
}
}

View file

@ -0,0 +1,78 @@
package fr.free.nrw.commons
import android.app.AlertDialog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import fr.free.nrw.commons.databinding.ActivityWelcomeBinding
import fr.free.nrw.commons.databinding.PopupForCopyrightBinding
import fr.free.nrw.commons.quiz.QuizActivity
import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour
class WelcomeActivity : BaseActivity() {
private var binding: ActivityWelcomeBinding? = null
private var isQuiz = false
/**
* Initialises exiting fields and dependencies
*
* @param savedInstanceState WelcomeActivity bundled data
*/
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityWelcomeBinding.inflate(layoutInflater)
setContentView(binding!!.root)
isQuiz = intent?.extras?.getBoolean("isQuiz", false) ?: false
// Enable skip button if beta flavor
if (isBetaFlavour) {
binding!!.finishTutorialButton.visibility = View.VISIBLE
val copyrightBinding = PopupForCopyrightBinding.inflate(layoutInflater)
val dialog = AlertDialog.Builder(this)
.setView(copyrightBinding.root)
.setCancelable(false)
.create()
dialog.show()
copyrightBinding.buttonOk.setOnClickListener { v: View? -> dialog.dismiss() }
}
val adapter = WelcomePagerAdapter()
binding!!.welcomePager.adapter = adapter
binding!!.welcomePagerIndicator.setViewPager(binding!!.welcomePager)
binding!!.finishTutorialButton.setOnClickListener { v: View? -> finishTutorial() }
}
public override fun onDestroy() {
if (isQuiz) {
startActivity(Intent(this, QuizActivity::class.java))
}
super.onDestroy()
}
override fun onBackPressed() {
if (binding!!.welcomePager.currentItem != 0) {
binding!!.welcomePager.setCurrentItem(binding!!.welcomePager.currentItem - 1, true)
} else {
if (defaultKvStore.getBoolean("firstrun", true)) {
finishAffinity()
} else {
super.onBackPressed()
}
}
}
fun finishTutorial() {
defaultKvStore.putBoolean("firstrun", false)
finish()
}
}
fun Context.startWelcome() {
startActivity(Intent(this, WelcomeActivity::class.java))
}

View file

@ -1,74 +0,0 @@
package fr.free.nrw.commons;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.viewpager.widget.PagerAdapter;
public class WelcomePagerAdapter extends PagerAdapter {
private static final int[] PAGE_LAYOUTS = new int[]{
R.layout.welcome_wikipedia,
R.layout.welcome_do_upload,
R.layout.welcome_dont_upload,
R.layout.welcome_image_example,
R.layout.welcome_final
};
/**
* Gets total number of layouts
* @return Number of layouts
*/
@Override
public int getCount() {
return PAGE_LAYOUTS.length;
}
/**
* Compares given view with provided object
* @param view Adapter view
* @param object Adapter object
* @return Equality between view and object
*/
@Override
public boolean isViewFromObject(View view, Object object) {
return (view == object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(container.getContext());
ViewGroup layout = (ViewGroup) inflater.inflate(PAGE_LAYOUTS[position], container, false);
// If final page
if (position == PAGE_LAYOUTS.length - 1) {
// Add link to more information
TextView moreInfo = layout.findViewById(R.id.welcomeInfo);
Utils.setUnderlinedText(moreInfo, R.string.welcome_help_button_text, container.getContext());
moreInfo.setOnClickListener(view -> Utils.handleWebUrl(
container.getContext(),
Uri.parse("https://commons.wikimedia.org/wiki/Help:Contents")
));
// Handle click of finishTutorialButton ("YES!" button) inside layout
layout.findViewById(R.id.finishTutorialButton)
.setOnClickListener(view -> ((WelcomeActivity) container.getContext()).finishTutorial());
}
container.addView(layout);
return layout;
}
/**
* Provides a way to remove an item from container
* @param container Adapter view group container
* @param position Index of item
* @param obj Adapter object
*/
@Override
public void destroyItem(ViewGroup container, int position, Object obj) {
container.removeView((View) obj);
}
}

View file

@ -0,0 +1,70 @@
package fr.free.nrw.commons
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.net.toUri
import androidx.viewpager.widget.PagerAdapter
import fr.free.nrw.commons.utils.UnderlineUtils.setUnderlinedText
import fr.free.nrw.commons.utils.handleWebUrl
class WelcomePagerAdapter : PagerAdapter() {
/**
* Gets total number of layouts
* @return Number of layouts
*/
override fun getCount(): Int = PAGE_LAYOUTS.size
/**
* Compares given view with provided object
* @param view Adapter view
* @param obj Adapter object
* @return Equality between view and object
*/
override fun isViewFromObject(view: View, obj: Any): Boolean = (view === obj)
/**
* Provides a way to remove an item from container
* @param container Adapter view group container
* @param position Index of item
* @param obj Adapter object
*/
override fun destroyItem(container: ViewGroup, position: Int, obj: Any) =
container.removeView(obj as View)
override fun instantiateItem(container: ViewGroup, position: Int): Any {
val inflater = LayoutInflater.from(container.context)
val layout = inflater.inflate(PAGE_LAYOUTS[position], container, false) as ViewGroup
// If final page
if (position == PAGE_LAYOUTS.size - 1) {
// Add link to more information
val moreInfo = layout.findViewById<TextView>(R.id.welcomeInfo)
setUnderlinedText(moreInfo, R.string.welcome_help_button_text)
moreInfo.setOnClickListener {
handleWebUrl(
container.context,
"https://commons.wikimedia.org/wiki/Help:Contents".toUri()
)
}
// Handle click of finishTutorialButton ("YES!" button) inside layout
layout.findViewById<View>(R.id.finishTutorialButton)
.setOnClickListener { view: View? -> (container.context as WelcomeActivity).finishTutorial() }
}
container.addView(layout)
return layout
}
companion object {
private val PAGE_LAYOUTS = intArrayOf(
R.layout.welcome_wikipedia,
R.layout.welcome_do_upload,
R.layout.welcome_dont_upload,
R.layout.welcome_image_example,
R.layout.welcome_final
)
}
}

View file

@ -25,7 +25,6 @@ import androidx.core.content.ContextCompat
import fr.free.nrw.commons.BuildConfig import fr.free.nrw.commons.BuildConfig
import fr.free.nrw.commons.CommonsApplication import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.login.LoginCallback import fr.free.nrw.commons.auth.login.LoginCallback
import fr.free.nrw.commons.auth.login.LoginClient import fr.free.nrw.commons.auth.login.LoginClient
import fr.free.nrw.commons.auth.login.LoginResult import fr.free.nrw.commons.auth.login.LoginResult
@ -38,6 +37,7 @@ import fr.free.nrw.commons.utils.ActivityUtils.startActivityWithFlags
import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour
import fr.free.nrw.commons.utils.SystemThemeUtils import fr.free.nrw.commons.utils.SystemThemeUtils
import fr.free.nrw.commons.utils.ViewUtil.hideKeyboard import fr.free.nrw.commons.utils.ViewUtil.hideKeyboard
import fr.free.nrw.commons.utils.handleWebUrl
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import timber.log.Timber import timber.log.Timber
import java.util.Locale import java.util.Locale
@ -254,10 +254,10 @@ class LoginActivity : AccountAuthenticatorActivity() {
} }
private fun forgotPassword() = private fun forgotPassword() =
Utils.handleWebUrl(this, Uri.parse(BuildConfig.FORGOT_PASSWORD_URL)) handleWebUrl(this, Uri.parse(BuildConfig.FORGOT_PASSWORD_URL))
private fun onPrivacyPolicyClicked() = private fun onPrivacyPolicyClicked() =
Utils.handleWebUrl(this, Uri.parse(BuildConfig.PRIVACY_POLICY_URL)) handleWebUrl(this, Uri.parse(BuildConfig.PRIVACY_POLICY_URL))
private fun signUp() = private fun signUp() =
startActivity(Intent(this, SignupActivity::class.java)) startActivity(Intent(this, SignupActivity::class.java))

View file

@ -7,7 +7,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.campaigns.models.Campaign import fr.free.nrw.commons.campaigns.models.Campaign
import fr.free.nrw.commons.contributions.MainActivity import fr.free.nrw.commons.contributions.MainActivity
import fr.free.nrw.commons.databinding.LayoutCampaginBinding import fr.free.nrw.commons.databinding.LayoutCampaginBinding
@ -16,6 +15,7 @@ import fr.free.nrw.commons.utils.CommonsDateUtil.getIso8601DateFormatShort
import fr.free.nrw.commons.utils.DateUtil.getExtraShortDateString import fr.free.nrw.commons.utils.DateUtil.getExtraShortDateString
import fr.free.nrw.commons.utils.SwipableCardView import fr.free.nrw.commons.utils.SwipableCardView
import fr.free.nrw.commons.utils.ViewUtil.showLongToast import fr.free.nrw.commons.utils.ViewUtil.showLongToast
import fr.free.nrw.commons.utils.handleWebUrl
import timber.log.Timber import timber.log.Timber
import java.text.ParseException import java.text.ParseException
@ -74,7 +74,7 @@ class CampaignView : SwipableCardView {
if (it.isWLMCampaign) { if (it.isWLMCampaign) {
((context) as MainActivity).showNearby() ((context) as MainActivity).showNearby()
} else { } else {
Utils.handleWebUrl(context, Uri.parse(it.link)) handleWebUrl(context, Uri.parse(it.link))
} }
} }
} }

View file

@ -26,7 +26,7 @@ class CampaignsPresenter @Inject constructor(
private val okHttpJsonApiClient: OkHttpJsonApiClient?, private val okHttpJsonApiClient: OkHttpJsonApiClient?,
@param:Named(IO_THREAD) private val ioScheduler: Scheduler, @param:Named(IO_THREAD) private val ioScheduler: Scheduler,
@param:Named(MAIN_THREAD) private val mainThreadScheduler: Scheduler @param:Named(MAIN_THREAD) private val mainThreadScheduler: Scheduler
) : BasePresenter<ICampaignsView?> { ) : BasePresenter<ICampaignsView> {
private var view: ICampaignsView? = null private var view: ICampaignsView? = null
private var disposable: Disposable? = null private var disposable: Disposable? = null
private var campaign: Campaign? = null private var campaign: Campaign? = null

View file

@ -1,11 +1,10 @@
package fr.free.nrw.commons.campaigns package fr.free.nrw.commons.campaigns
import fr.free.nrw.commons.MvpView
import fr.free.nrw.commons.campaigns.models.Campaign import fr.free.nrw.commons.campaigns.models.Campaign
/** /**
* Interface which defines the view contracts of the campaign view * Interface which defines the view contracts of the campaign view
*/ */
interface ICampaignsView : MvpView { interface ICampaignsView {
fun showCampaigns(campaign: Campaign?) fun showCampaigns(campaign: Campaign?)
} }

View file

@ -13,9 +13,9 @@ import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import fr.free.nrw.commons.BuildConfig.COMMONS_URL
import fr.free.nrw.commons.Media import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.ViewPagerAdapter import fr.free.nrw.commons.ViewPagerAdapter
import fr.free.nrw.commons.databinding.ActivityCategoryDetailsBinding import fr.free.nrw.commons.databinding.ActivityCategoryDetailsBinding
import fr.free.nrw.commons.explore.categories.media.CategoriesMediaFragment import fr.free.nrw.commons.explore.categories.media.CategoriesMediaFragment
@ -23,6 +23,9 @@ import fr.free.nrw.commons.explore.categories.parent.ParentCategoriesFragment
import fr.free.nrw.commons.explore.categories.sub.SubCategoriesFragment import fr.free.nrw.commons.explore.categories.sub.SubCategoriesFragment
import fr.free.nrw.commons.media.MediaDetailPagerFragment import fr.free.nrw.commons.media.MediaDetailPagerFragment
import fr.free.nrw.commons.theme.BaseActivity import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.wikidata.model.WikiSite
import fr.free.nrw.commons.wikidata.model.page.PageTitle
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@ -56,7 +59,7 @@ class CategoryDetailsActivity : BaseActivity(),
val view = binding.root val view = binding.root
setContentView(view) setContentView(view)
supportFragmentManager = getSupportFragmentManager() supportFragmentManager = getSupportFragmentManager()
viewPagerAdapter = ViewPagerAdapter(supportFragmentManager) viewPagerAdapter = ViewPagerAdapter(this, supportFragmentManager)
binding.viewPager.adapter = viewPagerAdapter binding.viewPager.adapter = viewPagerAdapter
binding.viewPager.offscreenPageLimit = 2 binding.viewPager.offscreenPageLimit = 2
binding.tabLayout.setupWithViewPager(binding.viewPager) binding.tabLayout.setupWithViewPager(binding.viewPager)
@ -80,8 +83,6 @@ class CategoryDetailsActivity : BaseActivity(),
* Set the fragments according to the tab selected in the viewPager. * Set the fragments according to the tab selected in the viewPager.
*/ */
private fun setTabs() { private fun setTabs() {
val fragmentList = mutableListOf<Fragment>()
val titleList = mutableListOf<String>()
categoriesMediaFragment = CategoriesMediaFragment() categoriesMediaFragment = CategoriesMediaFragment()
val subCategoryListFragment = SubCategoriesFragment() val subCategoryListFragment = SubCategoriesFragment()
val parentCategoriesFragment = ParentCategoriesFragment() val parentCategoriesFragment = ParentCategoriesFragment()
@ -96,13 +97,12 @@ class CategoryDetailsActivity : BaseActivity(),
viewModel.onCheckIfBookmarked(categoryName!!) viewModel.onCheckIfBookmarked(categoryName!!)
} }
fragmentList.add(categoriesMediaFragment)
titleList.add("MEDIA") viewPagerAdapter.setTabs(
fragmentList.add(subCategoryListFragment) R.string.title_for_media to categoriesMediaFragment,
titleList.add("SUBCATEGORIES") R.string.title_for_subcategories to subCategoryListFragment,
fragmentList.add(parentCategoriesFragment) R.string.title_for_parent_categories to parentCategoriesFragment
titleList.add("PARENT CATEGORIES") )
viewPagerAdapter.setTabData(fragmentList, titleList)
viewPagerAdapter.notifyDataSetChanged() viewPagerAdapter.notifyDataSetChanged()
} }
@ -199,8 +199,9 @@ class CategoryDetailsActivity : BaseActivity(),
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) { return when (item.itemId) {
R.id.menu_browser_current_category -> { R.id.menu_browser_current_category -> {
val title = Utils.getPageTitle(CATEGORY_PREFIX + categoryName) val title = PageTitle(CATEGORY_PREFIX + categoryName, WikiSite(COMMONS_URL))
Utils.handleWebUrl(this, Uri.parse(title.canonicalUri))
handleWebUrl(this, Uri.parse(title.canonicalUri))
true true
} }

View file

@ -9,7 +9,6 @@ import fr.free.nrw.commons.BasePresenter
interface ContributionsContract { interface ContributionsContract {
interface View { interface View {
fun showMessage(localizedMessage: String)
fun getContext(): Context? fun getContext(): Context?
} }

View file

@ -30,7 +30,6 @@ import androidx.work.WorkManager
import fr.free.nrw.commons.MapController.NearbyPlacesInfo import fr.free.nrw.commons.MapController.NearbyPlacesInfo
import fr.free.nrw.commons.Media import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.SessionManager import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.campaigns.CampaignView import fr.free.nrw.commons.campaigns.CampaignView
import fr.free.nrw.commons.campaigns.CampaignsPresenter import fr.free.nrw.commons.campaigns.CampaignsPresenter
@ -64,6 +63,9 @@ import fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween
import fr.free.nrw.commons.utils.NetworkUtils.isInternetConnectionEstablished import fr.free.nrw.commons.utils.NetworkUtils.isInternetConnectionEstablished
import fr.free.nrw.commons.utils.PermissionUtils.hasPermission import fr.free.nrw.commons.utils.PermissionUtils.hasPermission
import fr.free.nrw.commons.utils.ViewUtil.showLongToast import fr.free.nrw.commons.utils.ViewUtil.showLongToast
import fr.free.nrw.commons.utils.isMonumentsEnabled
import fr.free.nrw.commons.utils.wLMEndDate
import fr.free.nrw.commons.utils.wLMStartDate
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
@ -139,7 +141,7 @@ class ContributionsFragment : CommonsDaggerSupportFragment(), FragmentManager.On
private var wlmCampaign: Campaign? = null private var wlmCampaign: Campaign? = null
var userName: String? = null private var userName: String? = null
private var isUserProfile = false private var isUserProfile = false
private var mSensorManager: SensorManager? = null private var mSensorManager: SensorManager? = null
@ -242,8 +244,8 @@ class ContributionsFragment : CommonsDaggerSupportFragment(), FragmentManager.On
private fun initWLMCampaign() { private fun initWLMCampaign() {
wlmCampaign = Campaign( wlmCampaign = Campaign(
getString(R.string.wlm_campaign_title), getString(R.string.wlm_campaign_title),
getString(R.string.wlm_campaign_description), Utils.getWLMStartDate().toString(), getString(R.string.wlm_campaign_description), wLMStartDate,
Utils.getWLMEndDate().toString(), NearbyParentFragment.WLM_URL, true wLMEndDate, NearbyParentFragment.WLM_URL, true
) )
} }
@ -729,7 +731,7 @@ class ContributionsFragment : CommonsDaggerSupportFragment(), FragmentManager.On
* of campaigns on the campaigns card * of campaigns on the campaigns card
*/ */
private fun fetchCampaigns() { private fun fetchCampaigns() {
if (Utils.isMonumentsEnabled(Date())) { if (isMonumentsEnabled) {
if (binding != null) { if (binding != null) {
binding!!.campaignsView.setCampaign(wlmCampaign) binding!!.campaignsView.setCampaign(wlmCampaign)
binding!!.campaignsView.visibility = View.VISIBLE binding!!.campaignsView.visibility = View.VISIBLE
@ -743,10 +745,6 @@ class ContributionsFragment : CommonsDaggerSupportFragment(), FragmentManager.On
} }
} }
override fun showMessage(message: String) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
override fun showCampaigns(campaign: Campaign?) { override fun showCampaigns(campaign: Campaign?) {
if (campaign != null && !isUserProfile) { if (campaign != null && !isUserProfile) {
if (binding != null) { if (binding != null) {

View file

@ -15,7 +15,7 @@ class ContributionsListContract {
fun showNoContributionsUI(shouldShow: Boolean) fun showNoContributionsUI(shouldShow: Boolean)
} }
interface UserActionListener : BasePresenter<View?> { interface UserActionListener : BasePresenter<View> {
fun refreshList(swipeRefreshLayout: SwipeRefreshLayout?) fun refreshList(swipeRefreshLayout: SwipeRefreshLayout?)
} }
} }

View file

@ -21,7 +21,6 @@ import androidx.recyclerview.widget.SimpleItemAnimator
import fr.free.nrw.commons.Media import fr.free.nrw.commons.Media
import fr.free.nrw.commons.MediaDataExtractor import fr.free.nrw.commons.MediaDataExtractor
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.SessionManager import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.contributions.WikipediaInstructionsDialogFragment.Companion.newInstance import fr.free.nrw.commons.contributions.WikipediaInstructionsDialogFragment.Companion.newInstance
import fr.free.nrw.commons.databinding.FragmentContributionsListBinding import fr.free.nrw.commons.databinding.FragmentContributionsListBinding
@ -32,6 +31,9 @@ import fr.free.nrw.commons.profile.ProfileActivity
import fr.free.nrw.commons.ui.CustomFabController import fr.free.nrw.commons.ui.CustomFabController
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
import fr.free.nrw.commons.utils.SystemThemeUtils import fr.free.nrw.commons.utils.SystemThemeUtils
import fr.free.nrw.commons.utils.ViewUtil.showShortToast
import fr.free.nrw.commons.utils.copyToClipboard
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.wikidata.model.WikiSite import fr.free.nrw.commons.wikidata.model.WikiSite
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import javax.inject.Inject import javax.inject.Inject
@ -393,14 +395,13 @@ open class ContributionsListFragment : CommonsDaggerSupportFragment(), Contribut
*/ */
override fun onConfirmClicked(contribution: Contribution?, copyWikicode: Boolean) { override fun onConfirmClicked(contribution: Contribution?, copyWikicode: Boolean) {
if (copyWikicode) { if (copyWikicode) {
val wikicode = contribution!!.media.wikiCode requireContext().copyToClipboard("wikicode", contribution!!.media.wikiCode)
Utils.copy("wikicode", wikicode, context)
} }
val url = val url =
languageWikipediaSite!!.mobileUrl() + "/wiki/" + (contribution!!.wikidataPlace languageWikipediaSite!!.mobileUrl() + "/wiki/" + (contribution!!.wikidataPlace
?.getWikipediaPageTitle()) ?.getWikipediaPageTitle())
Utils.handleWebUrl(context, Uri.parse(url)) handleWebUrl(requireContext(), Uri.parse(url))
} }
fun getContributionStateAt(position: Int): Int { fun getContributionStateAt(position: Int): Int {

View file

@ -12,7 +12,6 @@ import androidx.fragment.app.FragmentManager
import androidx.work.ExistingWorkPolicy import androidx.work.ExistingWorkPolicy
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.WelcomeActivity
import fr.free.nrw.commons.auth.SessionManager import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.bookmarks.BookmarkFragment import fr.free.nrw.commons.bookmarks.BookmarkFragment
import fr.free.nrw.commons.contributions.ContributionsFragment.Companion.newInstance import fr.free.nrw.commons.contributions.ContributionsFragment.Companion.newInstance
@ -33,6 +32,7 @@ import fr.free.nrw.commons.notification.NotificationActivity.Companion.startYour
import fr.free.nrw.commons.notification.NotificationController import fr.free.nrw.commons.notification.NotificationController
import fr.free.nrw.commons.quiz.QuizChecker import fr.free.nrw.commons.quiz.QuizChecker
import fr.free.nrw.commons.settings.SettingsFragment import fr.free.nrw.commons.settings.SettingsFragment
import fr.free.nrw.commons.startWelcome
import fr.free.nrw.commons.theme.BaseActivity import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.upload.UploadProgressActivity import fr.free.nrw.commons.upload.UploadProgressActivity
import fr.free.nrw.commons.upload.worker.WorkRequestHelper.Companion.makeOneTimeWorkRequest import fr.free.nrw.commons.upload.worker.WorkRequestHelper.Companion.makeOneTimeWorkRequest
@ -517,7 +517,7 @@ after opening the app.
(!applicationKvStore!!.getBoolean("login_skipped")) (!applicationKvStore!!.getBoolean("login_skipped"))
) { ) {
defaultKvStore.putBoolean("inAppCameraFirstRun", true) defaultKvStore.putBoolean("inAppCameraFirstRun", true)
WelcomeActivity.startYourself(this) startWelcome()
} }
retryAllFailedUploads() retryAllFailedUploads()

View file

@ -53,7 +53,6 @@ class DeleteHelper @Inject constructor(
media: Media?, media: Media?,
reason: String? reason: String?
): Single<Boolean>? { ): Single<Boolean>? {
if(context == null && media == null) { if(context == null && media == null) {
return null return null
} }
@ -86,7 +85,6 @@ class DeleteHelper @Inject constructor(
* @return * @return
*/ */
private fun delete(media: Media, reason: String): Observable<Boolean> { private fun delete(media: Media, reason: String): Observable<Boolean> {
Timber.d("thread is delete %s", Thread.currentThread().name)
val summary = "Nominating ${media.filename} for deletion." val summary = "Nominating ${media.filename} for deletion."
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
val fileDeleteString = """ val fileDeleteString = """

View file

@ -2,21 +2,19 @@ package fr.free.nrw.commons.delete
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import fr.free.nrw.commons.utils.DateUtil
import java.util.Locale
import javax.inject.Inject
import javax.inject.Singleton
import fr.free.nrw.commons.Media import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.profile.achievements.FeedbackResponse
import fr.free.nrw.commons.auth.SessionManager import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
import fr.free.nrw.commons.utils.DateUtil
import fr.free.nrw.commons.utils.ViewUtilWrapper import fr.free.nrw.commons.utils.ViewUtilWrapper
import io.reactivex.Single import io.reactivex.Single
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.rx2.rxSingle
import timber.log.Timber import timber.log.Timber
import java.util.Locale
import javax.inject.Inject
import javax.inject.Singleton
/** /**
* This class handles the reason for deleting a Media object * This class handles the reason for deleting a Media object
@ -29,6 +27,8 @@ class ReasonBuilder @Inject constructor(
private val viewUtilWrapper: ViewUtilWrapper private val viewUtilWrapper: ViewUtilWrapper
) { ) {
private val defaultFileUsagePageSize = 10
/** /**
* To process the reason and append the media's upload date and uploaded_by_me string * To process the reason and append the media's upload date and uploaded_by_me string
* @param media * @param media
@ -39,7 +39,7 @@ class ReasonBuilder @Inject constructor(
if (media == null || reason == null) { if (media == null || reason == null) {
return Single.just("Not known") return Single.just("Not known")
} }
return fetchArticleNumber(media, reason) return getAndAppendFileUsage(media, reason)
} }
/** /**
@ -54,27 +54,36 @@ class ReasonBuilder @Inject constructor(
} }
} }
private fun fetchArticleNumber(media: Media, reason: String): Single<String> { private fun getAndAppendFileUsage(media: Media, reason: String): Single<String> {
return if (checkAccount()) { return rxSingle(context = Dispatchers.IO) {
okHttpJsonApiClient if (!checkAccount()) return@rxSingle ""
.getAchievements(sessionManager.userName)
.map { feedbackResponse -> appendArticlesUsed(feedbackResponse, media, reason) } try {
} else { val globalFileUsage = okHttpJsonApiClient.getGlobalFileUsages(
Single.just("") fileName = media.filename,
pageSize = defaultFileUsagePageSize
)
val globalUsages = globalFileUsage?.query?.pages?.sumOf { it.fileUsage.size } ?: 0
appendArticlesUsed(globalUsages, media, reason)
} catch (e: Exception) {
Timber.e(e, "Error fetching file usage")
throw e
}
} }
} }
/** /**
* Takes the uploaded_by_me string, the upload date, name of articles using images * Takes the uploaded_by_me string, the upload date, no. of articles using images
* and appends it to the received reason * and appends it to the received reason
* @param feedBack object * @param fileUsages No. of files/articles using this image
* @param media whose upload data is to be fetched * @param media whose upload data is to be fetched
* @param reason * @param reason string to be appended
*/ */
@SuppressLint("StringFormatInvalid") @SuppressLint("StringFormatInvalid")
private fun appendArticlesUsed(feedBack: FeedbackResponse, media: Media, reason: String): String { private fun appendArticlesUsed(fileUsages: Int, media: Media, reason: String): String {
val reason1Template = context.getString(R.string.uploaded_by_myself) val reason1Template = context.getString(R.string.uploaded_by_myself)
return reason + String.format(Locale.getDefault(), reason1Template, prettyUploadedDate(media), feedBack.articlesUsingImages) return reason + String.format(Locale.getDefault(), reason1Template, prettyUploadedDate(media), fileUsages)
.also { Timber.i("New Reason %s", it) } .also { Timber.i("New Reason %s", it) }
} }

View file

@ -1,6 +1,7 @@
package fr.free.nrw.commons.explore; package fr.free.nrw.commons.explore;
import static androidx.viewpager.widget.ViewPager.SCROLL_STATE_IDLE; import static androidx.viewpager.widget.ViewPager.SCROLL_STATE_IDLE;
import static fr.free.nrw.commons.ViewPagerAdapter.pairOf;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -23,10 +24,12 @@ import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.theme.BaseActivity; import fr.free.nrw.commons.theme.BaseActivity;
import fr.free.nrw.commons.utils.ActivityUtils; import fr.free.nrw.commons.utils.ActivityUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import kotlin.Pair;
public class ExploreFragment extends CommonsDaggerSupportFragment { public class ExploreFragment extends CommonsDaggerSupportFragment {
@ -70,7 +73,7 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
loadNearbyMapData(); loadNearbyMapData();
binding = FragmentExploreBinding.inflate(inflater, container, false); binding = FragmentExploreBinding.inflate(inflater, container, false);
viewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager(), viewPagerAdapter = new ViewPagerAdapter(requireContext(), getChildFragmentManager(),
FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
binding.viewPager.setAdapter(viewPagerAdapter); binding.viewPager.setAdapter(viewPagerAdapter);
@ -111,9 +114,6 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
* Sets the titles in the tabLayout and fragments in the viewPager * Sets the titles in the tabLayout and fragments in the viewPager
*/ */
public void setTabs() { public void setTabs() {
List<Fragment> fragmentList = new ArrayList<>();
List<String> titleList = new ArrayList<>();
Bundle featuredArguments = new Bundle(); Bundle featuredArguments = new Bundle();
featuredArguments.putString("categoryName", FEATURED_IMAGES_CATEGORY); featuredArguments.putString("categoryName", FEATURED_IMAGES_CATEGORY);
@ -133,19 +133,15 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
featuredRootFragment = new ExploreListRootFragment(featuredArguments); featuredRootFragment = new ExploreListRootFragment(featuredArguments);
mobileRootFragment = new ExploreListRootFragment(mobileArguments); mobileRootFragment = new ExploreListRootFragment(mobileArguments);
mapRootFragment = new ExploreMapRootFragment(mapArguments); mapRootFragment = new ExploreMapRootFragment(mapArguments);
fragmentList.add(featuredRootFragment);
titleList.add(getString(R.string.explore_tab_title_featured).toUpperCase(Locale.ROOT));
fragmentList.add(mobileRootFragment);
titleList.add(getString(R.string.explore_tab_title_mobile).toUpperCase(Locale.ROOT));
fragmentList.add(mapRootFragment);
titleList.add(getString(R.string.explore_tab_title_map).toUpperCase(Locale.ROOT));
((MainActivity) getActivity()).showTabs(); ((MainActivity) getActivity()).showTabs();
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false); ((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
viewPagerAdapter.setTabData(fragmentList, titleList); viewPagerAdapter.setTabs(
pairOf(R.string.explore_tab_title_featured, featuredRootFragment),
pairOf(R.string.explore_tab_title_mobile, mobileRootFragment),
pairOf(R.string.explore_tab_title_map, mapRootFragment)
);
viewPagerAdapter.notifyDataSetChanged(); viewPagerAdapter.notifyDataSetChanged();
} }

View file

@ -1,5 +1,7 @@
package fr.free.nrw.commons.explore; package fr.free.nrw.commons.explore;
import static fr.free.nrw.commons.ViewPagerAdapter.pairOf;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
@ -26,11 +28,13 @@ import fr.free.nrw.commons.utils.FragmentUtils;
import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.inject.Inject; import javax.inject.Inject;
import kotlin.Pair;
import timber.log.Timber; import timber.log.Timber;
/** /**
@ -65,7 +69,7 @@ public class SearchActivity extends BaseActivity
binding.toolbarSearch.setNavigationOnClickListener(v->onBackPressed()); binding.toolbarSearch.setNavigationOnClickListener(v->onBackPressed());
supportFragmentManager = getSupportFragmentManager(); supportFragmentManager = getSupportFragmentManager();
setSearchHistoryFragment(); setSearchHistoryFragment();
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager()); viewPagerAdapter = new ViewPagerAdapter(this, getSupportFragmentManager());
binding.viewPager.setAdapter(viewPagerAdapter); binding.viewPager.setAdapter(viewPagerAdapter);
binding.viewPager.setOffscreenPageLimit(2); // Because we want all the fragments to be alive binding.viewPager.setOffscreenPageLimit(2); // Because we want all the fragments to be alive
binding.tabLayout.setupWithViewPager(binding.viewPager); binding.tabLayout.setupWithViewPager(binding.viewPager);
@ -90,19 +94,15 @@ public class SearchActivity extends BaseActivity
* Sets the titles in the tabLayout and fragments in the viewPager * Sets the titles in the tabLayout and fragments in the viewPager
*/ */
public void setTabs() { public void setTabs() {
List<Fragment> fragmentList = new ArrayList<>();
List<String> titleList = new ArrayList<>();
searchMediaFragment = new SearchMediaFragment(); searchMediaFragment = new SearchMediaFragment();
searchDepictionsFragment = new SearchDepictionsFragment(); searchDepictionsFragment = new SearchDepictionsFragment();
searchCategoryFragment= new SearchCategoryFragment(); searchCategoryFragment= new SearchCategoryFragment();
fragmentList.add(searchMediaFragment);
titleList.add(getResources().getString(R.string.search_tab_title_media).toUpperCase(Locale.ROOT));
fragmentList.add(searchCategoryFragment);
titleList.add(getResources().getString(R.string.search_tab_title_categories).toUpperCase(Locale.ROOT));
fragmentList.add(searchDepictionsFragment);
titleList.add(getResources().getString(R.string.search_tab_title_depictions).toUpperCase(Locale.ROOT));
viewPagerAdapter.setTabData(fragmentList, titleList); viewPagerAdapter.setTabs(
pairOf(R.string.search_tab_title_media, searchMediaFragment),
pairOf(R.string.search_tab_title_categories, searchCategoryFragment),
pairOf(R.string.search_tab_title_depictions, searchDepictionsFragment)
);
viewPagerAdapter.notifyDataSetChanged(); viewPagerAdapter.notifyDataSetChanged();
getCompositeDisposable().add(RxSearchView.queryTextChanges(binding.searchBox) getCompositeDisposable().add(RxSearchView.queryTextChanges(binding.searchBox)
.takeUntil(RxView.detaches(binding.searchBox)) .takeUntil(RxView.detaches(binding.searchBox))

View file

@ -1,5 +1,8 @@
package fr.free.nrw.commons.explore.depictions; package fr.free.nrw.commons.explore.depictions;
import static fr.free.nrw.commons.ViewPagerAdapter.pairOf;
import static fr.free.nrw.commons.utils.UrlUtilsKt.handleWebUrl;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
@ -8,16 +11,11 @@ import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.FrameLayout;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
import fr.free.nrw.commons.Media; import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.ViewPagerAdapter; import fr.free.nrw.commons.ViewPagerAdapter;
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao; import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao;
import fr.free.nrw.commons.category.CategoryImagesCallback; import fr.free.nrw.commons.category.CategoryImagesCallback;
@ -34,8 +32,10 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import kotlin.Pair;
/** /**
* Activity to show depiction media, parent classes and child classes of depicted items in Explore * Activity to show depiction media, parent classes and child classes of depicted items in Explore
@ -69,7 +69,7 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
setContentView(binding.getRoot()); setContentView(binding.getRoot());
compositeDisposable = new CompositeDisposable(); compositeDisposable = new CompositeDisposable();
supportFragmentManager = getSupportFragmentManager(); supportFragmentManager = getSupportFragmentManager();
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager()); viewPagerAdapter = new ViewPagerAdapter(this, getSupportFragmentManager());
binding.viewPager.setAdapter(viewPagerAdapter); binding.viewPager.setAdapter(viewPagerAdapter);
binding.viewPager.setOffscreenPageLimit(2); binding.viewPager.setOffscreenPageLimit(2);
binding.tabLayout.setupWithViewPager(binding.viewPager); binding.tabLayout.setupWithViewPager(binding.viewPager);
@ -108,8 +108,6 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
* Set the fragments according to the tab selected in the viewPager. * Set the fragments according to the tab selected in the viewPager.
*/ */
private void setTabs() { private void setTabs() {
List<Fragment> fragmentList = new ArrayList<>();
List<String> titleList = new ArrayList<>();
depictionImagesListFragment = new DepictedImagesFragment(); depictionImagesListFragment = new DepictedImagesFragment();
ChildDepictionsFragment childDepictionsFragment = new ChildDepictionsFragment(); ChildDepictionsFragment childDepictionsFragment = new ChildDepictionsFragment();
ParentDepictionsFragment parentDepictionsFragment = new ParentDepictionsFragment(); ParentDepictionsFragment parentDepictionsFragment = new ParentDepictionsFragment();
@ -123,13 +121,12 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
parentDepictionsFragment.setArguments(arguments); parentDepictionsFragment.setArguments(arguments);
childDepictionsFragment.setArguments(arguments); childDepictionsFragment.setArguments(arguments);
} }
fragmentList.add(depictionImagesListFragment);
titleList.add(getResources().getString(R.string.title_for_media)); viewPagerAdapter.setTabs(
fragmentList.add(childDepictionsFragment); pairOf(R.string.title_for_media, depictionImagesListFragment),
titleList.add(getResources().getString(R.string.title_for_child_classes)); pairOf(R.string.title_for_subcategories, childDepictionsFragment),
fragmentList.add(parentDepictionsFragment); pairOf(R.string.title_for_parent_categories, parentDepictionsFragment)
titleList.add(getResources().getString(R.string.title_for_parent_classes)); );
viewPagerAdapter.setTabData(fragmentList, titleList);
binding.viewPager.setOffscreenPageLimit(2); binding.viewPager.setOffscreenPageLimit(2);
viewPagerAdapter.notifyDataSetChanged(); viewPagerAdapter.notifyDataSetChanged();
@ -249,7 +246,7 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
case R.id.browser_actions_menu_items: case R.id.browser_actions_menu_items:
String entityId=getIntent().getStringExtra("entityId"); String entityId=getIntent().getStringExtra("entityId");
Uri uri = Uri.parse("https://www.wikidata.org/wiki/" + entityId); Uri uri = Uri.parse("https://www.wikidata.org/wiki/" + entityId);
Utils.handleWebUrl(this, uri); handleWebUrl(this, uri);
return true; return true;
case R.id.menu_bookmark_current_item: case R.id.menu_bookmark_current_item:

View file

@ -1,8 +1,10 @@
package fr.free.nrw.commons.explore.map; package fr.free.nrw.commons.explore.map;
import androidx.annotation.NonNull;
import fr.free.nrw.commons.Media; import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.media.MediaClient; import fr.free.nrw.commons.media.MediaClient;
import java.util.Collections;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -23,6 +25,7 @@ public class ExploreMapCalls {
* @param currentLatLng coordinates of search location * @param currentLatLng coordinates of search location
* @return list of places obtained * @return list of places obtained
*/ */
@NonNull
List<Media> callCommonsQuery(final LatLng currentLatLng) { List<Media> callCommonsQuery(final LatLng currentLatLng) {
String coordinates = currentLatLng.getLatitude() + "|" + currentLatLng.getLongitude(); String coordinates = currentLatLng.getLatitude() + "|" + currentLatLng.getLongitude();
return mediaClient.getMediaListFromGeoSearch(coordinates).blockingGet(); return mediaClient.getMediaListFromGeoSearch(coordinates).blockingGet();

View file

@ -2,7 +2,9 @@ package fr.free.nrw.commons.explore.map;
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED; import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED;
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED; import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
import static fr.free.nrw.commons.utils.GeoCoordinatesKt.handleGeoCoordinates;
import static fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL; import static fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL;
import static fr.free.nrw.commons.utils.UrlUtilsKt.handleWebUrl;
import android.Manifest.permission; import android.Manifest.permission;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
@ -36,7 +38,6 @@ import fr.free.nrw.commons.BaseMarker;
import fr.free.nrw.commons.MapController; import fr.free.nrw.commons.MapController;
import fr.free.nrw.commons.Media; import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao; import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
import fr.free.nrw.commons.contributions.MainActivity; import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.databinding.FragmentExploreMapBinding; import fr.free.nrw.commons.databinding.FragmentExploreMapBinding;
@ -639,13 +640,13 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
*/ */
private void passInfoToSheet(final Place place) { private void passInfoToSheet(final Place place) {
binding.bottomSheetDetailsBinding.directionsButton.setOnClickListener( binding.bottomSheetDetailsBinding.directionsButton.setOnClickListener(
view -> Utils.handleGeoCoordinates(getActivity(), view -> handleGeoCoordinates(requireActivity(),
place.getLocation(), binding.mapView.getZoomLevelDouble())); place.getLocation(), binding.mapView.getZoomLevelDouble()));
binding.bottomSheetDetailsBinding.commonsButton.setVisibility( binding.bottomSheetDetailsBinding.commonsButton.setVisibility(
place.hasCommonsLink() ? View.VISIBLE : View.GONE); place.hasCommonsLink() ? View.VISIBLE : View.GONE);
binding.bottomSheetDetailsBinding.commonsButton.setOnClickListener( binding.bottomSheetDetailsBinding.commonsButton.setOnClickListener(
view -> Utils.handleWebUrl(getContext(), place.siteLinks.getCommonsLink())); view -> handleWebUrl(getContext(), place.siteLinks.getCommonsLink()));
int index = 0; int index = 0;
for (Media media : mediaList) { for (Media media : mediaList) {

View file

@ -14,6 +14,7 @@ import fr.free.nrw.commons.explore.map.ExploreMapController.NearbyBaseMarkerThum
import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType; import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType;
import fr.free.nrw.commons.nearby.Place;
import io.reactivex.Observable; import io.reactivex.Observable;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.List; import java.util.List;
@ -182,7 +183,7 @@ public class ExploreMapPresenter
exploreMapController exploreMapController
.loadAttractionsFromLocationToBaseMarkerOptions(explorePlacesInfo.currentLatLng, .loadAttractionsFromLocationToBaseMarkerOptions(explorePlacesInfo.currentLatLng,
// Curlatlang will be used to calculate distances // Curlatlang will be used to calculate distances
explorePlacesInfo.explorePlaceList, (List<Place>) explorePlacesInfo.explorePlaceList,
exploreMapFragmentView.getContext(), exploreMapFragmentView.getContext(),
this, this,
explorePlacesInfo); explorePlacesInfo);
@ -230,11 +231,7 @@ public class ExploreMapPresenter
mylocation.setLongitude(exploreMapFragmentView.getLastMapFocus().getLongitude()); mylocation.setLongitude(exploreMapFragmentView.getLastMapFocus().getLongitude());
Float distance = mylocation.distanceTo(dest_location); Float distance = mylocation.distanceTo(dest_location);
if (distance > 2000.0 * 3 / 4) { return !(distance > 2000.0 * 3 / 4);
return false;
} else {
return true;
}
} }
} }

View file

@ -30,7 +30,6 @@ import fr.free.nrw.commons.CameraPosition
import fr.free.nrw.commons.CommonsApplication import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.Media import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.SessionManager import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient import fr.free.nrw.commons.auth.csrf.CsrfTokenClient
import fr.free.nrw.commons.coordinates.CoordinateEditHelper import fr.free.nrw.commons.coordinates.CoordinateEditHelper
@ -45,6 +44,7 @@ import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.Compani
import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.Companion.LAST_ZOOM import fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.Companion.LAST_ZOOM
import fr.free.nrw.commons.utils.DialogUtil import fr.free.nrw.commons.utils.DialogUtil
import fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL import fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL
import fr.free.nrw.commons.utils.handleGeoCoordinates
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import org.osmdroid.tileprovider.tilesource.TileSourceFactory import org.osmdroid.tileprovider.tilesource.TileSourceFactory
@ -432,8 +432,8 @@ class LocationPickerActivity : BaseActivity(), LocationPermissionCallback {
position?.let { position?.let {
mapView?.zoomLevelDouble?.let { zoomLevel -> mapView?.zoomLevelDouble?.let { zoomLevel ->
Utils.handleGeoCoordinates(this, it, zoomLevel) handleGeoCoordinates(this, it, zoomLevel)
} ?: Utils.handleGeoCoordinates(this, it) } ?: handleGeoCoordinates(this, it)
} }
} }

View file

@ -74,11 +74,10 @@ import fr.free.nrw.commons.BuildConfig
import fr.free.nrw.commons.CameraPosition import fr.free.nrw.commons.CameraPosition
import fr.free.nrw.commons.CommonsApplication import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.CommonsApplication.Companion.instance import fr.free.nrw.commons.CommonsApplication.Companion.instance
import fr.free.nrw.commons.locationpicker.LocationPicker
import fr.free.nrw.commons.Media import fr.free.nrw.commons.Media
import fr.free.nrw.commons.MediaDataExtractor import fr.free.nrw.commons.MediaDataExtractor
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils import fr.free.nrw.commons.utils.UnderlineUtils
import fr.free.nrw.commons.actions.ThanksClient import fr.free.nrw.commons.actions.ThanksClient
import fr.free.nrw.commons.auth.SessionManager import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
@ -102,6 +101,7 @@ import fr.free.nrw.commons.explore.depictions.WikidataItemDetailsActivity
import fr.free.nrw.commons.kvstore.JsonKvStore import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.language.AppLanguageLookUpTable import fr.free.nrw.commons.language.AppLanguageLookUpTable
import fr.free.nrw.commons.location.LocationServiceManager import fr.free.nrw.commons.location.LocationServiceManager
import fr.free.nrw.commons.locationpicker.LocationPicker
import fr.free.nrw.commons.media.MediaDetailPagerFragment.MediaDetailProvider import fr.free.nrw.commons.media.MediaDetailPagerFragment.MediaDetailProvider
import fr.free.nrw.commons.profile.ProfileActivity import fr.free.nrw.commons.profile.ProfileActivity
import fr.free.nrw.commons.review.ReviewHelper import fr.free.nrw.commons.review.ReviewHelper
@ -116,8 +116,13 @@ import fr.free.nrw.commons.utils.LangCodeUtils.getLocalizedResources
import fr.free.nrw.commons.utils.PermissionUtils.PERMISSIONS_STORAGE import fr.free.nrw.commons.utils.PermissionUtils.PERMISSIONS_STORAGE
import fr.free.nrw.commons.utils.PermissionUtils.checkPermissionsAndPerformAction import fr.free.nrw.commons.utils.PermissionUtils.checkPermissionsAndPerformAction
import fr.free.nrw.commons.utils.PermissionUtils.hasPermission import fr.free.nrw.commons.utils.PermissionUtils.hasPermission
import fr.free.nrw.commons.utils.ViewUtil
import fr.free.nrw.commons.utils.ViewUtil.showShortToast import fr.free.nrw.commons.utils.ViewUtil.showShortToast
import fr.free.nrw.commons.utils.ViewUtilWrapper import fr.free.nrw.commons.utils.ViewUtilWrapper
import fr.free.nrw.commons.utils.copyToClipboard
import fr.free.nrw.commons.utils.handleGeoCoordinates
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.utils.setUnderlinedText
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage.Revision import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage.Revision
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.Single import io.reactivex.Single
@ -125,6 +130,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import timber.log.Timber import timber.log.Timber
import java.lang.String.format
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.Objects import java.util.Objects
@ -314,8 +320,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
_binding = FragmentMediaDetailBinding.inflate(inflater, container, false) _binding = FragmentMediaDetailBinding.inflate(inflater, container, false)
val view: View = binding.root val view: View = binding.root
binding.seeMore.setUnderlinedText(R.string.nominated_see_more)
Utils.setUnderlinedText(binding.seeMore, R.string.nominated_see_more, requireContext())
if (isCategoryImage) { if (isCategoryImage) {
binding.authorLinearLayout.visibility = View.VISIBLE binding.authorLinearLayout.visibility = View.VISIBLE
@ -907,7 +912,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
private fun onMediaDetailLicenceClicked() { private fun onMediaDetailLicenceClicked() {
val url: String? = media!!.licenseUrl val url: String? = media!!.licenseUrl
if (!StringUtils.isBlank(url) && activity != null) { if (!StringUtils.isBlank(url) && activity != null) {
Utils.handleWebUrl(activity, Uri.parse(url)) handleWebUrl(requireContext(), Uri.parse(url))
} else { } else {
viewUtil.showShortToast(requireActivity(), getString(R.string.null_url)) viewUtil.showShortToast(requireActivity(), getString(R.string.null_url))
} }
@ -915,17 +920,17 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
private fun onMediaDetailCoordinatesClicked() { private fun onMediaDetailCoordinatesClicked() {
if (media!!.coordinates != null && activity != null) { if (media!!.coordinates != null && activity != null) {
Utils.handleGeoCoordinates(activity, media!!.coordinates) handleGeoCoordinates(requireContext(), media!!.coordinates!!)
} }
} }
private fun onCopyWikicodeClicked() { private fun onCopyWikicodeClicked() {
val data: String = val data: String =
"[[" + media!!.filename + "|thumb|" + media!!.fallbackDescription + "]]" "[[" + media!!.filename + "|thumb|" + media!!.fallbackDescription + "]]"
Utils.copy("wikiCode", data, context) requireContext().copyToClipboard("wikiCode", data)
Timber.d("Generated wikidata copy code: %s", data) Timber.d("Generated wikidata copy code: %s", data)
Toast.makeText(context, getString(R.string.wikicode_copied), Toast.LENGTH_SHORT) Toast.makeText(requireContext(), getString(R.string.wikicode_copied), Toast.LENGTH_SHORT)
.show() .show()
} }
@ -1646,7 +1651,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
getString(R.string.cancel), getString(R.string.cancel),
{ {
val reason: String = input.text.toString() val reason: String = input.text.toString()
onDeleteClickeddialogtext(reason) onDeleteClickedDialogText(reason)
}, },
{}, {},
input input
@ -1700,26 +1705,48 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
resultSingle resultSingle
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { _ -> .subscribe(this::handleDeletionResult, this::handleDeletionError);
if (applicationKvStore.getBoolean( }
String.format(
NOMINATING_FOR_DELETION_MEDIA, media!!.imageUrl /**
), false * Disables Progress Bar and Update delete button text.
) */
) { private fun disableProgressBar() {
applicationKvStore.remove( activity?.run {
String.format( runOnUiThread(Runnable {
NOMINATING_FOR_DELETION_MEDIA, binding.progressBarDeletion.visibility = View.GONE
media!!.imageUrl })
) } ?: return // Prevent NullPointerException when fragment is not attached to activity
) }
callback!!.nominatingForDeletion(index)
} private fun handleDeletionResult(success: Boolean) {
} if (success) {
binding.nominateDeletion.text = getString(R.string.nominated_for_deletion_btn)
ViewUtil.showLongSnackbar(requireView(), getString(R.string.nominated_for_deletion))
disableProgressBar()
checkAndClearDeletionFlag()
} else {
disableProgressBar()
}
}
private fun handleDeletionError(throwable: Throwable) {
throwable.printStackTrace()
disableProgressBar()
checkAndClearDeletionFlag()
}
private fun checkAndClearDeletionFlag() {
if (applicationKvStore
.getBoolean(format(NOMINATING_FOR_DELETION_MEDIA, media!!.imageUrl), false)
) {
applicationKvStore.remove(format(NOMINATING_FOR_DELETION_MEDIA, media!!.imageUrl))
callback!!.nominatingForDeletion(index)
}
} }
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
private fun onDeleteClickeddialogtext(reason: String) { private fun onDeleteClickedDialogText(reason: String) {
applicationKvStore.putBoolean( applicationKvStore.putBoolean(
String.format( String.format(
NOMINATING_FOR_DELETION_MEDIA, NOMINATING_FOR_DELETION_MEDIA,
@ -1736,27 +1763,12 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
resultSingletext resultSingletext
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { _ -> .subscribe(this::handleDeletionResult, this::handleDeletionError);
if (applicationKvStore.getBoolean(
String.format(
NOMINATING_FOR_DELETION_MEDIA, media!!.imageUrl
), false
)
) {
applicationKvStore.remove(
String.format(
NOMINATING_FOR_DELETION_MEDIA,
media!!.imageUrl
)
)
callback!!.nominatingForDeletion(index)
}
}
} }
private fun onSeeMoreClicked() { private fun onSeeMoreClicked() {
if (binding.nominatedDeletionBanner.visibility == View.VISIBLE && activity != null) { if (binding.nominatedDeletionBanner.visibility == View.VISIBLE && activity != null) {
Utils.handleWebUrl(activity, Uri.parse(media!!.pageTitle.mobileUri)) handleWebUrl(requireContext(), Uri.parse(media!!.pageTitle.mobileUri))
} }
} }

View file

@ -1,6 +1,6 @@
package fr.free.nrw.commons.media; package fr.free.nrw.commons.media;
import static fr.free.nrw.commons.Utils.handleWebUrl; import static fr.free.nrw.commons.utils.UrlUtilsKt.handleWebUrl;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
@ -31,7 +31,7 @@ import com.google.android.material.snackbar.Snackbar;
import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Media; import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.utils.ClipboardUtils;
import fr.free.nrw.commons.auth.SessionManager; import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.bookmarks.models.Bookmark; import fr.free.nrw.commons.bookmarks.models.Bookmark;
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider; import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesContentProvider;
@ -216,7 +216,7 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
return true; return true;
case R.id.menu_copy_link: case R.id.menu_copy_link:
String uri = m.getPageTitle().getCanonicalUri(); String uri = m.getPageTitle().getCanonicalUri();
Utils.copy("shareLink", uri, requireContext()); ClipboardUtils.copy("shareLink", uri, requireContext());
Timber.d("Copied share link to clipboard: %s", uri); Timber.d("Copied share link to clipboard: %s", uri);
Toast.makeText(requireContext(), getString(R.string.menu_link_copied), Toast.makeText(requireContext(), getString(R.string.menu_link_copied),
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();

View file

@ -1,6 +1,6 @@
package fr.free.nrw.commons.media package fr.free.nrw.commons.media
import fr.free.nrw.commons.OkHttpConnectionFactory.UnsuccessfulResponseInterceptor.SUPPRESS_ERROR_LOG_HEADER import fr.free.nrw.commons.SUPPRESS_ERROR_LOG_HEADER
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
import io.reactivex.Single import io.reactivex.Single
import retrofit2.http.GET import retrofit2.http.GET

View file

@ -281,6 +281,7 @@ class OkHttpJsonApiClient @Inject constructor(
FeedbackResponse::class.java FeedbackResponse::class.java
) )
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace()
return@fromCallable FeedbackResponse(0, 0, 0, FeaturedImages(0, 0), 0, "") return@fromCallable FeedbackResponse(0, 0, 0, FeaturedImages(0, 0), 0, "")
} }
} }

View file

@ -18,7 +18,6 @@ import fr.free.nrw.commons.BuildConfig
import fr.free.nrw.commons.CommonsApplication import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.CommonsApplication.ActivityLogoutListener import fr.free.nrw.commons.CommonsApplication.ActivityLogoutListener
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.WelcomeActivity
import fr.free.nrw.commons.actions.PageEditClient import fr.free.nrw.commons.actions.PageEditClient
import fr.free.nrw.commons.databinding.FragmentMoreBottomSheetBinding import fr.free.nrw.commons.databinding.FragmentMoreBottomSheetBinding
import fr.free.nrw.commons.di.ApplicationlessInjection import fr.free.nrw.commons.di.ApplicationlessInjection
@ -32,6 +31,7 @@ import fr.free.nrw.commons.logging.CommonsLogSender
import fr.free.nrw.commons.profile.ProfileActivity import fr.free.nrw.commons.profile.ProfileActivity
import fr.free.nrw.commons.review.ReviewActivity import fr.free.nrw.commons.review.ReviewActivity
import fr.free.nrw.commons.settings.SettingsActivity import fr.free.nrw.commons.settings.SettingsActivity
import fr.free.nrw.commons.startWelcome
import io.reactivex.Single import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
@ -241,7 +241,7 @@ class MoreBottomSheetFragment : BottomSheetDialogFragment() {
} }
fun onTutorialClicked() { fun onTutorialClicked() {
WelcomeActivity.startYourself(requireActivity()) requireContext().startWelcome()
} }
fun onSettingsClicked() { fun onSettingsClicked() {

View file

@ -1,10 +1,14 @@
package fr.free.nrw.commons.nearby; package fr.free.nrw.commons.nearby;
import static java.util.Collections.emptyList;
import android.location.Location; import android.location.Location;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import fr.free.nrw.commons.nearby.model.NearbyQueryParams; import fr.free.nrw.commons.nearby.model.NearbyQueryParams;
import fr.free.nrw.commons.nearby.model.NearbyQueryParams.Radial;
import fr.free.nrw.commons.nearby.model.NearbyQueryParams.Rectangular;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
@ -46,13 +50,14 @@ public class NearbyPlaces {
* @param customQuery * @param customQuery
* @return list of places obtained * @return list of places obtained
*/ */
@NonNull
List<Place> radiusExpander(final LatLng currentLatLng, final String lang, List<Place> radiusExpander(final LatLng currentLatLng, final String lang,
final boolean returnClosestResult, @Nullable final String customQuery) throws Exception { final boolean returnClosestResult, @Nullable final String customQuery) throws Exception {
final int minResults; final int minResults;
final double maxRadius; final double maxRadius;
List<Place> places = Collections.emptyList(); List<Place> places = emptyList();
// If returnClosestResult is true, then this means that we are trying to get closest point // If returnClosestResult is true, then this means that we are trying to get closest point
// to use in cardView in Contributions fragment // to use in cardView in Contributions fragment
@ -113,6 +118,7 @@ public class NearbyPlaces {
* @return A list of places obtained from the Wikidata query. * @return A list of places obtained from the Wikidata query.
* @throws Exception If an error occurs during the retrieval process. * @throws Exception If an error occurs during the retrieval process.
*/ */
@NonNull
public List<Place> getFromWikidataQuery( public List<Place> getFromWikidataQuery(
final fr.free.nrw.commons.location.LatLng centerPoint, final fr.free.nrw.commons.location.LatLng centerPoint,
final fr.free.nrw.commons.location.LatLng screenTopRight, final fr.free.nrw.commons.location.LatLng screenTopRight,
@ -120,11 +126,11 @@ public class NearbyPlaces {
final boolean shouldQueryForMonuments, final boolean shouldQueryForMonuments,
@Nullable final String customQuery) throws Exception { @Nullable final String customQuery) throws Exception {
if (customQuery != null) { if (customQuery != null) {
return okHttpJsonApiClient final List<Place> nearbyPlaces = okHttpJsonApiClient.getNearbyPlaces(
.getNearbyPlaces( new Rectangular(screenTopRight, screenBottomLeft), lang,
new NearbyQueryParams.Rectangular(screenTopRight, screenBottomLeft), lang,
shouldQueryForMonuments, shouldQueryForMonuments,
customQuery); customQuery);
return nearbyPlaces != null ? nearbyPlaces : emptyList();
} }
final int lowerLimit = 1000, upperLimit = 1500; final int lowerLimit = 1000, upperLimit = 1500;
@ -141,9 +147,10 @@ public class NearbyPlaces {
final int itemCount = okHttpJsonApiClient.getNearbyItemCount( final int itemCount = okHttpJsonApiClient.getNearbyItemCount(
new NearbyQueryParams.Rectangular(screenTopRight, screenBottomLeft)); new NearbyQueryParams.Rectangular(screenTopRight, screenBottomLeft));
if (itemCount < upperLimit) { if (itemCount < upperLimit) {
return okHttpJsonApiClient.getNearbyPlaces( final List<Place> nearbyPlaces = okHttpJsonApiClient.getNearbyPlaces(
new NearbyQueryParams.Rectangular(screenTopRight, screenBottomLeft), lang, new Rectangular(screenTopRight, screenBottomLeft), lang,
shouldQueryForMonuments, null); shouldQueryForMonuments, null);
return nearbyPlaces != null ? nearbyPlaces : emptyList();
} }
} }
@ -175,9 +182,10 @@ public class NearbyPlaces {
maxRadius = targetRadius - 1; maxRadius = targetRadius - 1;
} }
} }
return okHttpJsonApiClient.getNearbyPlaces( final List<Place> nearbyPlaces = okHttpJsonApiClient.getNearbyPlaces(
new NearbyQueryParams.Radial(centerPoint, targetRadius / 100f), lang, shouldQueryForMonuments, new Radial(centerPoint, targetRadius / 100f), lang, shouldQueryForMonuments,
null); null);
return nearbyPlaces != null ? nearbyPlaces : emptyList();
} }
/** /**

View file

@ -10,12 +10,13 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.LoginActivity import fr.free.nrw.commons.auth.LoginActivity
import fr.free.nrw.commons.contributions.ContributionController import fr.free.nrw.commons.contributions.ContributionController
import fr.free.nrw.commons.kvstore.JsonKvStore import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.nearby.Place import fr.free.nrw.commons.nearby.Place
import fr.free.nrw.commons.utils.ActivityUtils import fr.free.nrw.commons.utils.ActivityUtils
import fr.free.nrw.commons.utils.handleGeoCoordinates
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.wikidata.WikidataConstants import fr.free.nrw.commons.wikidata.WikidataConstants
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -104,7 +105,7 @@ class CommonPlaceClickActions
fun onDirectionsClicked(): (Place) -> Unit = fun onDirectionsClicked(): (Place) -> Unit =
{ {
Utils.handleGeoCoordinates(activity, it.getLocation()) handleGeoCoordinates(activity, it.getLocation())
} }
private fun storeSharedPrefs(selectedPlace: Place) { private fun storeSharedPrefs(selectedPlace: Place) {
@ -113,7 +114,7 @@ class CommonPlaceClickActions
} }
private fun openWebView(link: Uri): Boolean { private fun openWebView(link: Uri): Boolean {
Utils.handleWebUrl(activity, link) handleWebUrl(activity, link)
return true return true
} }

View file

@ -58,12 +58,10 @@ import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.MapController.NearbyPlacesInfo import fr.free.nrw.commons.MapController.NearbyPlacesInfo
import fr.free.nrw.commons.Media import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
import fr.free.nrw.commons.contributions.ContributionController import fr.free.nrw.commons.contributions.ContributionController
import fr.free.nrw.commons.contributions.MainActivity import fr.free.nrw.commons.contributions.MainActivity
import fr.free.nrw.commons.contributions.MainActivity.ActiveFragment import fr.free.nrw.commons.contributions.MainActivity.ActiveFragment
import fr.free.nrw.commons.customselector.ui.selector.ImageLoader
import fr.free.nrw.commons.databinding.FragmentNearbyParentBinding import fr.free.nrw.commons.databinding.FragmentNearbyParentBinding
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
import fr.free.nrw.commons.filepicker.FilePicker import fr.free.nrw.commons.filepicker.FilePicker
@ -76,7 +74,6 @@ import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType
import fr.free.nrw.commons.location.LocationUpdateListener import fr.free.nrw.commons.location.LocationUpdateListener
import fr.free.nrw.commons.media.MediaClient import fr.free.nrw.commons.media.MediaClient
import fr.free.nrw.commons.media.MediaDetailPagerFragment import fr.free.nrw.commons.media.MediaDetailPagerFragment
import fr.free.nrw.commons.media.MediaDetailPagerFragment.MediaDetailProvider
import fr.free.nrw.commons.navtab.NavTab import fr.free.nrw.commons.navtab.NavTab
import fr.free.nrw.commons.nearby.BottomSheetAdapter import fr.free.nrw.commons.nearby.BottomSheetAdapter
import fr.free.nrw.commons.nearby.BottomSheetAdapter.ItemClickListener import fr.free.nrw.commons.nearby.BottomSheetAdapter.ItemClickListener
@ -105,6 +102,10 @@ import fr.free.nrw.commons.utils.NearbyFABUtils.removeAnchorFromFAB
import fr.free.nrw.commons.utils.NetworkUtils.isInternetConnectionEstablished import fr.free.nrw.commons.utils.NetworkUtils.isInternetConnectionEstablished
import fr.free.nrw.commons.utils.SystemThemeUtils import fr.free.nrw.commons.utils.SystemThemeUtils
import fr.free.nrw.commons.utils.ViewUtil.showLongToast import fr.free.nrw.commons.utils.ViewUtil.showLongToast
import fr.free.nrw.commons.utils.copyToClipboard
import fr.free.nrw.commons.utils.handleGeoCoordinates
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.utils.isMonumentsEnabled
import fr.free.nrw.commons.wikidata.WikidataConstants import fr.free.nrw.commons.wikidata.WikidataConstants
import fr.free.nrw.commons.wikidata.WikidataEditListener import fr.free.nrw.commons.wikidata.WikidataEditListener
import fr.free.nrw.commons.wikidata.WikidataEditListener.WikidataP18EditListener import fr.free.nrw.commons.wikidata.WikidataEditListener.WikidataP18EditListener
@ -123,6 +124,7 @@ import org.osmdroid.views.CustomZoomButtonsController
import org.osmdroid.views.MapView import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.MapEventsOverlay import org.osmdroid.views.overlay.MapEventsOverlay
import org.osmdroid.views.overlay.Marker import org.osmdroid.views.overlay.Marker
import org.osmdroid.views.overlay.Overlay
import org.osmdroid.views.overlay.ScaleBarOverlay import org.osmdroid.views.overlay.ScaleBarOverlay
import org.osmdroid.views.overlay.ScaleDiskOverlay import org.osmdroid.views.overlay.ScaleDiskOverlay
import org.osmdroid.views.overlay.TilesOverlay import org.osmdroid.views.overlay.TilesOverlay
@ -139,7 +141,6 @@ import java.util.UUID
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Named import javax.inject.Named
import javax.sql.DataSource
import kotlin.concurrent.Volatile import kotlin.concurrent.Volatile
@ -267,6 +268,9 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
private var dataList: MutableList<BottomSheetItem>? = null private var dataList: MutableList<BottomSheetItem>? = null
private var bottomSheetAdapter: BottomSheetAdapter? = null private var bottomSheetAdapter: BottomSheetAdapter? = null
private var userLocationOverlay: Overlay? = null
private var userLocationErrorOverlay: Overlay? = null
private val galleryPickLauncherForResult = private val galleryPickLauncherForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
controller?.handleActivityResultWithCallback( controller?.handleActivityResultWithCallback(
@ -463,7 +467,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
} }
} }
_isDarkTheme = systemThemeUtils?.isDeviceInNightMode() == true _isDarkTheme = systemThemeUtils?.isDeviceInNightMode() == true
if (Utils.isMonumentsEnabled(Date())) { if (isMonumentsEnabled) {
binding?.rlContainerWlmMonthMessage?.visibility = View.VISIBLE binding?.rlContainerWlmMonthMessage?.visibility = View.VISIBLE
} else { } else {
binding?.rlContainerWlmMonthMessage?.visibility = View.GONE binding?.rlContainerWlmMonthMessage?.visibility = View.GONE
@ -724,7 +728,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
val targetP = GeoPoint(target.latitude, target.longitude) val targetP = GeoPoint(target.latitude, target.longitude)
mapCenter = targetP mapCenter = targetP
binding?.map?.controller?.setCenter(targetP) binding?.map?.controller?.setCenter(targetP)
recenterMarkerToPosition(targetP) updateUserLocationOverlays(targetP, true)
if (!isCameFromExploreMap()) { if (!isCameFromExploreMap()) {
moveCameraToPosition(targetP) moveCameraToPosition(targetP)
} }
@ -832,7 +836,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
loadAnimations() loadAnimations()
setBottomSheetCallbacks() setBottomSheetCallbacks()
addActionToTitle() addActionToTitle()
if (!Utils.isMonumentsEnabled(Date())) { if (!isMonumentsEnabled) {
NearbyFilterState.setWlmSelected(false) NearbyFilterState.setWlmSelected(false)
} }
} }
@ -1013,11 +1017,10 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
*/ */
private fun addActionToTitle() { private fun addActionToTitle() {
binding!!.bottomSheetDetails.title.setOnLongClickListener { view -> binding!!.bottomSheetDetails.title.setOnLongClickListener { view ->
Utils.copy( requireContext().copyToClipboard(
"place", binding!!.bottomSheetDetails.title.text.toString(), "place", binding!!.bottomSheetDetails.title.text.toString()
context
) )
Toast.makeText(context, fr.free.nrw.commons.R.string.text_copy, Toast.LENGTH_SHORT) Toast.makeText(requireContext(), fr.free.nrw.commons.R.string.text_copy, Toast.LENGTH_SHORT)
.show() .show()
true true
} }
@ -1576,7 +1579,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
searchLatLng, searchLatLng,
false, false,
true, true,
Utils.isMonumentsEnabled(Date()), isMonumentsEnabled,
customQuery customQuery
) )
} }
@ -1629,7 +1632,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
searchLatLng, searchLatLng,
false, false,
true, true,
Utils.isMonumentsEnabled(Date()), isMonumentsEnabled,
customQuery customQuery
) )
} }
@ -1863,6 +1866,8 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
lastKnownLocation = latLng lastKnownLocation = latLng
NearbyController.currentLocation = lastKnownLocation NearbyController.currentLocation = lastKnownLocation
presenter!!.updateMapAndList(locationChangeType) presenter!!.updateMapAndList(locationChangeType)
updateUserLocationOverlays(GeoPoint(latLng.latitude, latLng.longitude), true)
} }
override fun onLocationChangedSignificantly(latLng: LatLng) { override fun onLocationChangedSignificantly(latLng: LatLng) {
@ -2644,43 +2649,14 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
*/ */
override fun clearAllMarkers() { override fun clearAllMarkers() {
binding!!.map.overlayManager.clear() binding!!.map.overlayManager.clear()
binding!!.map.invalidate()
val geoPoint = mapCenter var geoPoint = mapCenter
if (geoPoint != null) { val lastLatLng = locationManager.getLastLocation()
val diskOverlay = if (lastLatLng != null) {
ScaleDiskOverlay( geoPoint = GeoPoint(lastLatLng.latitude, lastLatLng.longitude)
this.context,
geoPoint, 2000, UnitOfMeasure.foot
)
val circlePaint = Paint()
circlePaint.color = Color.rgb(128, 128, 128)
circlePaint.style = Paint.Style.STROKE
circlePaint.strokeWidth = 2f
diskOverlay.setCirclePaint2(circlePaint)
val diskPaint = Paint()
diskPaint.color = Color.argb(40, 128, 128, 128)
diskPaint.style = Paint.Style.FILL_AND_STROKE
diskOverlay.setCirclePaint1(diskPaint)
diskOverlay.setDisplaySizeMin(900)
diskOverlay.setDisplaySizeMax(1700)
binding!!.map.overlays.add(diskOverlay)
val startMarker = Marker(
binding!!.map
)
startMarker.position = geoPoint
startMarker.setAnchor(
Marker.ANCHOR_CENTER,
Marker.ANCHOR_BOTTOM
)
startMarker.icon =
getDrawable(
this.requireContext(),
fr.free.nrw.commons.R.drawable.current_location_marker
)
startMarker.title = "Your Location"
startMarker.textLabelFontSize = 24
binding!!.map.overlays.add(startMarker)
} }
updateUserLocationOverlays(geoPoint, false)
val scaleBarOverlay = ScaleBarOverlay(binding!!.map) val scaleBarOverlay = ScaleBarOverlay(binding!!.map)
scaleBarOverlay.setScaleBarOffset(15, 25) scaleBarOverlay.setScaleBarOffset(15, 25)
val barPaint = Paint() val barPaint = Paint()
@ -2690,6 +2666,7 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
binding!!.map.overlays.add(scaleBarOverlay) binding!!.map.overlays.add(scaleBarOverlay)
binding!!.map.overlays.add(mapEventsOverlay) binding!!.map.overlays.add(mapEventsOverlay)
binding!!.map.setMultiTouchControls(true) binding!!.map.setMultiTouchControls(true)
binding!!.map.invalidate()
} }
/** /**
@ -2700,45 +2677,149 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
private fun recenterMarkerToPosition(geoPoint: GeoPoint?) { private fun recenterMarkerToPosition(geoPoint: GeoPoint?) {
geoPoint?.let { geoPoint?.let {
binding?.map?.controller?.setCenter(it) binding?.map?.controller?.setCenter(it)
val overlays = binding?.map?.overlays ?: return@let
// Remove markers and disks using index-based removal updateUserLocationOverlays(it, true);
var i = 0
while (i < overlays.size) {
when (overlays[i]) {
is Marker, is ScaleDiskOverlay -> overlays.removeAt(i)
else -> i++
}
}
// Add disk overlay
ScaleDiskOverlay(context, it, 2000, UnitOfMeasure.foot).apply {
setCirclePaint2(Paint().apply {
color = Color.rgb(128, 128, 128)
style = Paint.Style.STROKE
strokeWidth = 2f
})
setCirclePaint1(Paint().apply {
color = Color.argb(40, 128, 128, 128)
style = Paint.Style.FILL_AND_STROKE
})
setDisplaySizeMin(900)
setDisplaySizeMax(1700)
overlays.add(this)
}
// Add marker
Marker(binding?.map).apply {
position = it
setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM)
icon = getDrawable(context, R.drawable.current_location_marker)
title = "Your Location"
textLabelFontSize = 24
overlays.add(this)
}
} }
} }
/**
* Updates the user current location overlays (both the location and error overlays) by
* replacing any existing location overlays with new overlays at the given GeoPoint. If there
* are no existing location and error overlays, then new overlays are added.
*
* @param geoPoint The GeoPoint representing the user's current location.
* @param invalidate If true, the map overlays will be invalidated after the user
* location overlays are updated/added. If false, the overlays will not be invalidated.
*/
private fun updateUserLocationOverlays(geoPoint: GeoPoint?, invalidate: Boolean) {
geoPoint?.let{
updateUserLocationOverlay(geoPoint)
updateUserLocationErrorOverlay(geoPoint)
}
if (invalidate) {
binding!!.map.invalidate()
}
}
/**
* Updates the user location error overlay by either replacing it with or adding a new one.
*
* If the user location error overlay is null, the new overlay is added. If the
* overlay is not null, it is replaced by the new overlay.
*
* @param geoPoint The GeoPoint representing the user's location
*/
private fun updateUserLocationErrorOverlay(geoPoint: GeoPoint) {
val overlays = binding?.map?.overlays ?: return
// Multiply accuracy by 2 to get 95% confidence interval
val accuracy = getCurrentLocationAccuracy() * 2
val overlay = createCurrentLocationErrorOverlay(this.context, geoPoint,
(accuracy).toInt(), UnitOfMeasure.meter)
val index = overlays.indexOf(userLocationErrorOverlay)
if (userLocationErrorOverlay == null || index == -1) {
overlays.add(overlay)
} else {
overlays[index] = overlay
}
userLocationErrorOverlay = overlay
}
/**
* Updates the user location overlay by either replacing it with or adding a new one.
*
* If the user location overlay is null, the new overlay is added. If the
* overlay is not null, it is replaced by the new overlay.
*
* @param geoPoint The GeoPoint representing the user's location
*/
private fun updateUserLocationOverlay(geoPoint: GeoPoint) {
val overlays = binding?.map?.overlays ?: return
val overlay = createCurrentLocationOverlay(geoPoint)
val index = overlays.indexOf(userLocationOverlay)
if (userLocationOverlay == null || index == -1) {
overlays.add(overlay)
} else {
overlays[index] = overlay
}
userLocationOverlay = overlay
}
/**
* @return The accuracy of the current location with a confidence at the 68th percentile.
* Units are in meters. Returning 0 may indicate failure.
*/
private fun getCurrentLocationAccuracy(): Float {
var accuracy = 0f
val lastLocation = locationManager.getLastLocation()
if (lastLocation != null) {
accuracy = lastLocation.accuracy
}
return accuracy
}
/**
* Creates the current location overlay
*
* @param geoPoint The GeoPoint where the current location overlay will be placed.
*
* @return The current location overlay as a Marker
*/
private fun createCurrentLocationOverlay(geoPoint: GeoPoint): Marker {
val currentLocationOverlay = Marker(
binding!!.map
)
currentLocationOverlay.position = geoPoint
currentLocationOverlay.icon =
getDrawable(
this.requireContext(),
fr.free.nrw.commons.R.drawable.current_location_marker
)
currentLocationOverlay.title = "Your Location"
currentLocationOverlay.textLabelFontSize = 24
currentLocationOverlay.setAnchor(0.5f, 0.5f)
return currentLocationOverlay
}
/**
* Creates the location error overlay to show the user how accurate the current location
* overlay is. The edge of the disk is the 95% confidence interval.
*
* @param context The Android context
* @param point The user's location as a GeoPoint
* @param value The radius of the disk
* @param unitOfMeasure The unit of measurement of the value/disk radius.
*
* @return The location error overlay as a ScaleDiskOverlay.
*/
private fun createCurrentLocationErrorOverlay(context: Context?, point: GeoPoint, value: Int,
unitOfMeasure: UnitOfMeasure): ScaleDiskOverlay {
val scaleDisk = ScaleDiskOverlay(context, point, value, unitOfMeasure)
scaleDisk.setCirclePaint2(Paint().apply {
color = Color.rgb(128, 128, 128)
style = Paint.Style.STROKE
strokeWidth = 2f
})
scaleDisk.setCirclePaint1(Paint().apply {
color = Color.argb(40, 128, 128, 128)
style = Paint.Style.FILL_AND_STROKE
})
return scaleDisk
}
private fun moveCameraToPosition(geoPoint: GeoPoint) { private fun moveCameraToPosition(geoPoint: GeoPoint) {
binding!!.map.controller.animateTo(geoPoint) binding!!.map.controller.animateTo(geoPoint)
} }
@ -2772,14 +2853,14 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
R.drawable.ic_directions_black_24dp -> { R.drawable.ic_directions_black_24dp -> {
selectedPlace?.let { selectedPlace?.let {
Utils.handleGeoCoordinates(this.context, it.getLocation()) handleGeoCoordinates(requireContext(), it.getLocation())
binding?.map?.zoomLevelDouble ?: 0.0 binding?.map?.zoomLevelDouble ?: 0.0
} }
} }
R.drawable.ic_wikidata_logo_24dp -> { R.drawable.ic_wikidata_logo_24dp -> {
selectedPlace?.siteLinks?.wikidataLink?.let { selectedPlace?.siteLinks?.wikidataLink?.let {
Utils.handleWebUrl(this.context, it) handleWebUrl(requireContext(), it)
} }
} }
@ -2797,13 +2878,13 @@ class NearbyParentFragment : CommonsDaggerSupportFragment(),
R.drawable.ic_wikipedia_logo_24dp -> { R.drawable.ic_wikipedia_logo_24dp -> {
selectedPlace?.siteLinks?.wikipediaLink?.let { selectedPlace?.siteLinks?.wikipediaLink?.let {
Utils.handleWebUrl(this.context, it) handleWebUrl(requireContext(), it)
} }
} }
R.drawable.ic_commons_icon_vector -> { R.drawable.ic_commons_icon_vector -> {
selectedPlace?.siteLinks?.commonsLink?.let { selectedPlace?.siteLinks?.commonsLink?.let {
Utils.handleWebUrl(this.context, it) handleWebUrl(requireContext(), it)
} }
} }

View file

@ -351,6 +351,7 @@ class NearbyParentFragmentPresenter
pic = repoPlace.pic ?: "" pic = repoPlace.pic ?: ""
exists = repoPlace.exists ?: true exists = repoPlace.exists ?: true
longDescription = repoPlace.longDescription ?: "" longDescription = repoPlace.longDescription ?: ""
language = repoPlace.language
} }
} else { } else {
indicesToUpdate.add(i) indicesToUpdate.add(i)

View file

@ -13,7 +13,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import fr.free.nrw.commons.CommonsApplication import fr.free.nrw.commons.CommonsApplication
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.SessionManager import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
import fr.free.nrw.commons.databinding.ActivityNotificationBinding import fr.free.nrw.commons.databinding.ActivityNotificationBinding
@ -22,6 +21,7 @@ import fr.free.nrw.commons.notification.models.NotificationType
import fr.free.nrw.commons.theme.BaseActivity import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.utils.NetworkUtils import fr.free.nrw.commons.utils.NetworkUtils
import fr.free.nrw.commons.utils.ViewUtil import fr.free.nrw.commons.utils.ViewUtil
import fr.free.nrw.commons.utils.handleWebUrl
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
@ -197,7 +197,7 @@ class NotificationActivity : BaseActivity() {
private fun handleUrl(url: String?) { private fun handleUrl(url: String?) {
if (url.isNullOrEmpty()) return if (url.isNullOrEmpty()) return
Utils.handleWebUrl(this, Uri.parse(url)) handleWebUrl(this, Uri.parse(url))
} }
private fun setItems(notificationList: List<Notification>?) { private fun setItems(notificationList: List<Notification>?) {

View file

@ -3,16 +3,17 @@ package fr.free.nrw.commons.profile
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.* import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.ViewPagerAdapter import fr.free.nrw.commons.ViewPagerAdapter
import fr.free.nrw.commons.auth.SessionManager import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.contributions.ContributionsFragment import fr.free.nrw.commons.contributions.ContributionsFragment
@ -23,7 +24,7 @@ import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.utils.DialogUtil import fr.free.nrw.commons.utils.DialogUtil
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.util.* import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
/** /**
@ -71,7 +72,7 @@ class ProfileActivity : BaseActivity() {
title = userName title = userName
shouldShowContributions = intent.getBooleanExtra(KEY_SHOULD_SHOW_CONTRIBUTIONS, false) shouldShowContributions = intent.getBooleanExtra(KEY_SHOULD_SHOW_CONTRIBUTIONS, false)
viewPagerAdapter = ViewPagerAdapter(supportFragmentManager) viewPagerAdapter = ViewPagerAdapter(this, supportFragmentManager)
binding.viewPager.adapter = viewPagerAdapter binding.viewPager.adapter = viewPagerAdapter
binding.tabLayout.setupWithViewPager(binding.viewPager) binding.tabLayout.setupWithViewPager(binding.viewPager)
setTabs() setTabs()
@ -83,39 +84,23 @@ class ProfileActivity : BaseActivity() {
} }
private fun setTabs() { private fun setTabs() {
val fragmentList = mutableListOf<Fragment>()
val titleList = mutableListOf<String>()
// Add Achievements tab
achievementsFragment = AchievementsFragment().apply { achievementsFragment = AchievementsFragment().apply {
arguments = Bundle().apply { arguments = bundleOf(KEY_USERNAME to userName)
putString(KEY_USERNAME, userName)
}
} }
fragmentList.add(achievementsFragment)
titleList.add(resources.getString(R.string.achievements_tab_title).uppercase())
// Add Leaderboard tab
leaderboardFragment = LeaderboardFragment().apply { leaderboardFragment = LeaderboardFragment().apply {
arguments = Bundle().apply { arguments = bundleOf(KEY_USERNAME to userName)
putString(KEY_USERNAME, userName)
}
} }
fragmentList.add(leaderboardFragment)
titleList.add(resources.getString(R.string.leaderboard_tab_title).uppercase(Locale.ROOT))
// Add Contributions tab
contributionsFragment = ContributionsFragment().apply { contributionsFragment = ContributionsFragment().apply {
arguments = Bundle().apply { arguments = bundleOf(KEY_USERNAME to userName)
putString(KEY_USERNAME, userName)
}
}
contributionsFragment?.let {
fragmentList.add(it)
titleList.add(getString(R.string.contributions_fragment).uppercase(Locale.ROOT))
} }
viewPagerAdapter.setTabData(fragmentList, titleList) viewPagerAdapter.setTabs(
R.string.achievements_tab_title to achievementsFragment,
R.string.leaderboard_tab_title to leaderboardFragment,
R.string.contributions_fragment to contributionsFragment!!
)
viewPagerAdapter.notifyDataSetChanged() viewPagerAdapter.notifyDataSetChanged()
} }
@ -133,7 +118,7 @@ class ProfileActivity : BaseActivity() {
return when (item.itemId) { return when (item.itemId) {
R.id.share_app_icon -> { R.id.share_app_icon -> {
val rootView = window.decorView.findViewById<View>(android.R.id.content) val rootView = window.decorView.findViewById<View>(android.R.id.content)
val screenShot = Utils.getScreenShot(rootView) val screenShot = getScreenShot(rootView)
if (screenShot == null) { if (screenShot == null) {
Log.e("ERROR", "ScreenShot is null") Log.e("ERROR", "ScreenShot is null")
return false return false
@ -212,6 +197,24 @@ class ProfileActivity : BaseActivity() {
binding.tabLayout.visibility = if (isVisible) View.VISIBLE else View.GONE binding.tabLayout.visibility = if (isVisible) View.VISIBLE else View.GONE
} }
/**
* To take screenshot of the screen and return it in Bitmap format
*
* @param view
* @return
*/
fun getScreenShot(view: View): Bitmap? {
val screenView = view.rootView
screenView.isDrawingCacheEnabled = true
val drawingCache = screenView.drawingCache
if (drawingCache != null) {
val bitmap = Bitmap.createBitmap(drawingCache)
screenView.isDrawingCacheEnabled = false
return bitmap
}
return null
}
companion object { companion object {
const val KEY_USERNAME = "username" const val KEY_USERNAME = "username"
const val KEY_SHOULD_SHOW_CONTRIBUTIONS = "shouldShowContributions" const val KEY_SHOULD_SHOW_CONTRIBUTIONS = "shouldShowContributions"

View file

@ -15,7 +15,6 @@ import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.badge.BadgeUtils import com.google.android.material.badge.BadgeUtils
import com.google.android.material.badge.ExperimentalBadgeUtils import com.google.android.material.badge.ExperimentalBadgeUtils
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.auth.SessionManager import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.databinding.FragmentAchievementsBinding import fr.free.nrw.commons.databinding.FragmentAchievementsBinding
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
@ -27,6 +26,7 @@ import fr.free.nrw.commons.utils.ConfigUtils.isBetaFlavour
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
import fr.free.nrw.commons.utils.ViewUtil.showDismissibleSnackBar import fr.free.nrw.commons.utils.ViewUtil.showDismissibleSnackBar
import fr.free.nrw.commons.utils.ViewUtil.showLongToast import fr.free.nrw.commons.utils.ViewUtil.showLongToast
import fr.free.nrw.commons.utils.handleWebUrl
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
@ -524,7 +524,7 @@ class AchievementsFragment : CommonsDaggerSupportFragment(){
getString(R.string.ok), getString(R.string.ok),
getString(R.string.read_help_link), getString(R.string.read_help_link),
{}, {},
{ Utils.handleWebUrl(requireContext(), Uri.parse(helpLinkUrl)) }, { handleWebUrl(requireContext(), Uri.parse(helpLinkUrl)) },
null null
) )
} }

View file

@ -33,9 +33,7 @@ import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.PermissionToken import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import fr.free.nrw.commons.BuildConfig.MOBILE_META_URL
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.activity.SingleWebViewActivity import fr.free.nrw.commons.activity.SingleWebViewActivity
import fr.free.nrw.commons.campaigns.CampaignView import fr.free.nrw.commons.campaigns.CampaignView
import fr.free.nrw.commons.contributions.ContributionController import fr.free.nrw.commons.contributions.ContributionController
@ -53,6 +51,7 @@ import fr.free.nrw.commons.utils.DialogUtil
import fr.free.nrw.commons.utils.PermissionUtils import fr.free.nrw.commons.utils.PermissionUtils
import fr.free.nrw.commons.utils.StringUtil import fr.free.nrw.commons.utils.StringUtil
import fr.free.nrw.commons.utils.ViewUtil import fr.free.nrw.commons.utils.ViewUtil
import fr.free.nrw.commons.utils.handleWebUrl
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Named import javax.inject.Named
@ -239,7 +238,10 @@ class SettingsFragment : PreferenceFragmentCompat() {
val betaTesterPreference: Preference? = findPreference("becomeBetaTester") val betaTesterPreference: Preference? = findPreference("becomeBetaTester")
betaTesterPreference?.setOnPreferenceClickListener { betaTesterPreference?.setOnPreferenceClickListener {
Utils.handleWebUrl(requireActivity(), Uri.parse(getString(R.string.beta_opt_in_link))) handleWebUrl(
requireActivity(),
Uri.parse(getString(R.string.beta_opt_in_link))
)
true true
} }
@ -296,7 +298,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
getString(R.string.ok), getString(R.string.ok),
getString(R.string.read_help_link), getString(R.string.read_help_link),
{ }, { },
{ Utils.handleWebUrl(requireContext(), Uri.parse(GET_CONTENT_PICKER_HELP_URL)) }, { handleWebUrl(requireContext(), Uri.parse(GET_CONTENT_PICKER_HELP_URL)) },
null null
) )
} }

View file

@ -1,11 +1,11 @@
package fr.free.nrw.commons.upload package fr.free.nrw.commons.upload
import android.content.Context import android.content.Context
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.contributions.Contribution import fr.free.nrw.commons.contributions.Contribution
import fr.free.nrw.commons.filepicker.UploadableFile.DateTimeWithSource import fr.free.nrw.commons.filepicker.UploadableFile.DateTimeWithSource
import fr.free.nrw.commons.settings.Prefs.Licenses import fr.free.nrw.commons.settings.Prefs.Licenses
import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha import fr.free.nrw.commons.utils.ConfigUtils.getVersionNameWithSha
import fr.free.nrw.commons.utils.getWikiLovesMonumentsYear
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
@ -49,7 +49,7 @@ class PageContentsCreator @Inject constructor(private val context: Context) {
String.format( String.format(
Locale.ENGLISH, Locale.ENGLISH,
"{{Wiki Loves Monuments %d|1= %s}}\n", "{{Wiki Loves Monuments %d|1= %s}}\n",
Utils.getWikiLovesMonumentsYear(Calendar.getInstance()), getWikiLovesMonumentsYear(Calendar.getInstance()),
contribution.countryCode contribution.countryCode
) )
) )

View file

@ -1,10 +1,10 @@
package fr.free.nrw.commons.upload package fr.free.nrw.commons.upload
import android.net.Uri import android.net.Uri
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.filepicker.MimeTypeMapWrapper.Companion.getExtensionFromMimeType import fr.free.nrw.commons.filepicker.MimeTypeMapWrapper.Companion.getExtensionFromMimeType
import fr.free.nrw.commons.nearby.Place import fr.free.nrw.commons.nearby.Place
import fr.free.nrw.commons.utils.ImageUtils import fr.free.nrw.commons.utils.ImageUtils
import fr.free.nrw.commons.utils.fixExtension
class UploadItem( class UploadItem(
var mediaUri: Uri?, var mediaUri: Uri?,
@ -32,7 +32,7 @@ class UploadItem(
* languages have been entered, the first language is used. * languages have been entered, the first language is used.
*/ */
val filename: String val filename: String
get() = Utils.fixExtension( get() = fixExtension(
uploadMediaDetails[0].captionText, uploadMediaDetails[0].captionText,
getExtensionFromMimeType(mimeType) getExtensionFromMimeType(mimeType)
) )

View file

@ -28,8 +28,6 @@ class UploadProgressActivity : BaseActivity() {
@Inject @Inject
lateinit var contributionDao: ContributionDao lateinit var contributionDao: ContributionDao
val fragmentList: MutableList<Fragment> = ArrayList()
val titleList: MutableList<String> = ArrayList()
var isPaused = true var isPaused = true
var isPendingIconsVisible = true var isPendingIconsVisible = true
var isErrorIconsVisisble = false var isErrorIconsVisisble = false
@ -38,7 +36,7 @@ class UploadProgressActivity : BaseActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityUploadProgressBinding.inflate(layoutInflater) binding = ActivityUploadProgressBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
viewPagerAdapter = ViewPagerAdapter(supportFragmentManager) viewPagerAdapter = ViewPagerAdapter(this, supportFragmentManager)
binding.uploadProgressViewPager.setAdapter(viewPagerAdapter) binding.uploadProgressViewPager.setAdapter(viewPagerAdapter)
binding.uploadProgressViewPager.setId(R.id.upload_progress_view_pager) binding.uploadProgressViewPager.setId(R.id.upload_progress_view_pager)
binding.uploadProgressTabLayout.setupWithViewPager(binding.uploadProgressViewPager) binding.uploadProgressTabLayout.setupWithViewPager(binding.uploadProgressViewPager)
@ -81,11 +79,10 @@ class UploadProgressActivity : BaseActivity() {
pendingUploadsFragment = PendingUploadsFragment() pendingUploadsFragment = PendingUploadsFragment()
failedUploadsFragment = FailedUploadsFragment() failedUploadsFragment = FailedUploadsFragment()
fragmentList.add(pendingUploadsFragment!!) viewPagerAdapter!!.setTabs(
titleList.add(getString(R.string.pending)) R.string.pending to pendingUploadsFragment!!,
fragmentList.add(failedUploadsFragment!!) R.string.failed to failedUploadsFragment!!
titleList.add(getString(R.string.failed)) )
viewPagerAdapter!!.setTabData(fragmentList, titleList)
viewPagerAdapter!!.notifyDataSetChanged() viewPagerAdapter!!.notifyDataSetChanged()
} }

View file

@ -16,11 +16,13 @@ import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.TextView import android.widget.TextView
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.databinding.FragmentMediaLicenseBinding import fr.free.nrw.commons.databinding.FragmentMediaLicenseBinding
import fr.free.nrw.commons.upload.UploadActivity import fr.free.nrw.commons.upload.UploadActivity
import fr.free.nrw.commons.upload.UploadBaseFragment import fr.free.nrw.commons.upload.UploadBaseFragment
import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog import fr.free.nrw.commons.utils.DialogUtil.showAlertDialog
import fr.free.nrw.commons.utils.handleWebUrl
import fr.free.nrw.commons.utils.toLicenseName
import fr.free.nrw.commons.utils.toLicenseUrl
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -126,20 +128,20 @@ class MediaLicenseFragment : UploadBaseFragment(), MediaLicenseContract.View {
} }
override fun setSelectedLicense(license: String?) { override fun setSelectedLicense(license: String?) {
var position = licenses!!.indexOf(getString(Utils.licenseNameFor(license))) var position = license?.let { licenses!!.indexOf(getString(it.toLicenseName())) } ?: -1
// Check if position is valid // Check if position is valid
if (position < 0) { if (position < 0) {
Timber.d("Invalid position: %d. Using default licenses", position) Timber.d("Invalid position: %d. Using default licenses", position)
position = licenses!!.size - 1 position = licenses!!.size - 1
} else {
Timber.d("Position: %d %s", position, getString(Utils.licenseNameFor(license)))
} }
binding.spinnerLicenseList.setSelection(position) binding.spinnerLicenseList.setSelection(position)
} }
override fun updateLicenseSummary(selectedLicense: String?, numberOfItems: Int) { override fun updateLicenseSummary(selectedLicense: String?, numberOfItems: Int) {
val licenseHyperLink = "<a href='" + Utils.licenseUrlFor(selectedLicense) + "'>" + if (selectedLicense == null) return
getString(Utils.licenseNameFor(selectedLicense)) + "</a><br>"
val licenseHyperLink = "<a href='" + selectedLicense.toLicenseUrl() + "'>" +
getString(selectedLicense.toLicenseName()) + "</a><br>"
setTextViewHTML( setTextViewHTML(
binding.tvShareLicenseSummary, resources binding.tvShareLicenseSummary, resources
@ -184,7 +186,7 @@ class MediaLicenseFragment : UploadBaseFragment(), MediaLicenseContract.View {
} }
private fun launchBrowser(hyperLink: String) = private fun launchBrowser(hyperLink: String) =
Utils.handleWebUrl(context, Uri.parse(hyperLink)) handleWebUrl(requireContext(), Uri.parse(hyperLink))
override fun onDestroyView() { override fun onDestroyView() {
presenter.onDetachView() presenter.onDetachView()

View file

@ -1,9 +1,9 @@
package fr.free.nrw.commons.upload.license package fr.free.nrw.commons.upload.license
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.kvstore.JsonKvStore import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.repository.UploadRepository import fr.free.nrw.commons.repository.UploadRepository
import fr.free.nrw.commons.settings.Prefs import fr.free.nrw.commons.settings.Prefs
import fr.free.nrw.commons.utils.toLicenseName
import timber.log.Timber import timber.log.Timber
import java.lang.reflect.Method import java.lang.reflect.Method
import java.lang.reflect.Proxy import java.lang.reflect.Proxy
@ -34,12 +34,14 @@ class MediaLicensePresenter @Inject constructor(
val licenses = repository.getLicenses() val licenses = repository.getLicenses()
view.setLicenses(licenses) view.setLicenses(licenses)
var selectedLicense = defaultKVStore.getString( //CC_BY_SA_4 is the default one used by the commons web app
var selectedLicense: String = defaultKVStore.getString(
Prefs.DEFAULT_LICENSE, Prefs.DEFAULT_LICENSE,
Prefs.Licenses.CC_BY_SA_4 Prefs.Licenses.CC_BY_SA_4
) //CC_BY_SA_4 is the default one used by the commons web app ) ?: Prefs.Licenses.CC_BY_SA_4
try { //I have to make sure that the stored default license was not one of the deprecated one's try { //I have to make sure that the stored default license was not one of the deprecated one's
Utils.licenseNameFor(selectedLicense) selectedLicense.toLicenseName()
} catch (exception: IllegalStateException) { } catch (exception: IllegalStateException) {
Timber.e(exception) Timber.e(exception)
selectedLicense = Prefs.Licenses.CC_BY_SA_4 selectedLicense = Prefs.Licenses.CC_BY_SA_4

View file

@ -54,7 +54,7 @@ interface UploadMediaDetailsContract {
fun showBadImagePopup(errorCode: Int, index: Int, uploadItem: UploadItem) fun showBadImagePopup(errorCode: Int, index: Int, uploadItem: UploadItem)
} }
interface UserActionListener : BasePresenter<View?> { interface UserActionListener : BasePresenter<View> {
fun setupBasicKvStoreFactory(factory: (String) -> BasicKvStore) fun setupBasicKvStoreFactory(factory: (String) -> BasicKvStore)
fun receiveImage( fun receiveImage(

View file

@ -107,7 +107,10 @@ class UploadMediaPresenter @Inject constructor(
view.showProgress(false) view.showProgress(false)
val gpsCoords = uploadItem.gpsCoords val gpsCoords = uploadItem.gpsCoords
val hasImageCoordinates = gpsCoords != null && gpsCoords.imageCoordsExists val hasImageCoordinates = gpsCoords != null && gpsCoords.imageCoordsExists
if (hasImageCoordinates && place == null) {
// Only check for nearby places if image has coordinates AND no place was pre-selected
// This prevents the popup from appearing when uploading from Nearby feature
if (hasImageCoordinates && place == null && uploadItem.place == null) {
checkNearbyPlaces(uploadItem) checkNearbyPlaces(uploadItem)
} }
}, { throwable: Throwable? -> }, { throwable: Throwable? ->

View file

@ -472,7 +472,10 @@ class UploadWorker(
if (wikiDataPlace != null) { if (wikiDataPlace != null) {
if (!contribution.hasInvalidLocation()) { if (!contribution.hasInvalidLocation()) {
var revisionID: Long? = null var revisionID: Long? = null
val p18WasSkipped = !wikiDataPlace.imageValue.isNullOrBlank()
try { try {
if (!p18WasSkipped) {
// Only set P18 if the place does not already have a picture
revisionID = revisionID =
wikidataEditService.createClaim( wikidataEditService.createClaim(
wikiDataPlace, wikiDataPlace,
@ -489,9 +492,11 @@ class UploadWorker(
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.blockingAwait() .blockingAwait()
Timber.d("Updated WikiItem place ${place.name} with image ${place.pic}") Timber.d("Updated WikiItem place ${place.name} with image ${place.pic}")
}
} }
showSuccessNotification(contribution)
} }
// Always show success notification, whether P18 was set or skipped
showSuccessNotification(contribution)
} catch (exception: Exception) { } catch (exception: Exception) {
Timber.e(exception) Timber.e(exception)
} }
@ -500,6 +505,7 @@ class UploadWorker(
wikidataEditService.handleImageClaimResult( wikidataEditService.handleImageClaimResult(
contribution.wikidataPlace!!, contribution.wikidataPlace!!,
revisionID, revisionID,
p18WasSkipped = p18WasSkipped
) )
} }
} else { } else {

View file

@ -0,0 +1,20 @@
package fr.free.nrw.commons.utils
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.CLIPBOARD_SERVICE
object ClipboardUtils {
// Convenience for Java usages - remove when they are converted.
@JvmStatic
fun copy(label: String?, text: String?, context: Context) {
context.copyToClipboard(label, text)
}
}
fun Context.copyToClipboard(label: String?, text: String?) {
with(getSystemService(CLIPBOARD_SERVICE) as ClipboardManager) {
setPrimaryClip(ClipData.newPlainText(label, text))
}
}

View file

@ -0,0 +1,38 @@
package fr.free.nrw.commons.utils
import java.util.Locale
import java.util.regex.Pattern
private val jpegPattern = Pattern.compile("\\.jpeg$", Pattern.CASE_INSENSITIVE)
/**
* Adds extension to filename. Converts to .jpg if system provides .jpeg, adds .jpg if no extension detected
* @param theTitle File name
* @param ext Correct extension
* @return File with correct extension
*/
fun fixExtension(theTitle: String, ext: String?): String {
var result = theTitle
var extension = ext
// People are used to ".jpg" more than ".jpeg" which the system gives us.
if (extension != null && extension.lowercase() == "jpeg") {
extension = "jpg"
}
result = jpegPattern.matcher(result).replaceFirst(".jpg")
if (extension != null &&
!result.lowercase(Locale.getDefault()).endsWith("." + extension.lowercase())
) {
result += ".$extension"
}
// If extension is still null, make it jpg. (Hotfix for https://github.com/commons-app/apps-android-commons/issues/228)
// If title has an extension in it, if won't be true
if (extension == null && result.lastIndexOf(".") <= 0) {
extension = "jpg"
result += ".$extension"
}
return result
}

View file

@ -0,0 +1,27 @@
package fr.free.nrw.commons.utils
import android.content.Context
import android.content.Intent
import fr.free.nrw.commons.R
import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.utils.ViewUtil.showShortToast
/**
* Util function to handle geo coordinates with specified zoom level. It no longer depends on
* google maps and any app capable of handling the map intent can handle it
*
* @param context The context for launching intent
* @param latLng The latitude and longitude of the location
* @param zoomLevel The zoom level
*/
fun handleGeoCoordinates(
context: Context, latLng: LatLng,
zoomLevel: Double = 16.0
) {
val mapIntent = Intent(Intent.ACTION_VIEW, latLng.getGmmIntentUri(zoomLevel))
if (mapIntent.resolveActivity(context.packageManager) != null) {
context.startActivity(mapIntent)
} else {
showShortToast(context, context.getString(R.string.map_application_missing))
}
}

View file

@ -0,0 +1,31 @@
package fr.free.nrw.commons.utils
import fr.free.nrw.commons.R
import fr.free.nrw.commons.settings.Prefs
/**
* Generates licence name with given ID
* @return Name of license
*/
fun String.toLicenseName(): Int = when (this) {
Prefs.Licenses.CC_BY_3 -> R.string.license_name_cc_by
Prefs.Licenses.CC_BY_4 -> R.string.license_name_cc_by_four
Prefs.Licenses.CC_BY_SA_3 -> R.string.license_name_cc_by_sa
Prefs.Licenses.CC_BY_SA_4 -> R.string.license_name_cc_by_sa_four
Prefs.Licenses.CC0 -> R.string.license_name_cc0
else -> throw IllegalStateException("Unrecognized license value: $this")
}
/**
* Generates license url with given ID
* @return Url of license
*/
fun String.toLicenseUrl(): String = when (this) {
Prefs.Licenses.CC_BY_3 -> "https://creativecommons.org/licenses/by/3.0/"
Prefs.Licenses.CC_BY_4 -> "https://creativecommons.org/licenses/by/4.0/"
Prefs.Licenses.CC_BY_SA_3 -> "https://creativecommons.org/licenses/by-sa/3.0/"
Prefs.Licenses.CC_BY_SA_4 -> "https://creativecommons.org/licenses/by-sa/4.0/"
Prefs.Licenses.CC0 -> "https://creativecommons.org/publicdomain/zero/1.0/"
else -> throw IllegalStateException("Unrecognized license value: $this")
}

View file

@ -0,0 +1,39 @@
package fr.free.nrw.commons.utils
import java.util.Calendar
import java.util.Date
/**
* Get the start date of wlm monument
* For this release we are hardcoding it to be 1st September
* @return
*/
const val wLMStartDate: String = "1 Sep"
/***
* Get the end date of wlm monument
* For this release we are hardcoding it to be 31st October
* @return
*/
const val wLMEndDate: String = "30 Sep"
/**
* For now we are enabling the monuments only when the date lies between 1 Sept & 31 OCt
*/
val isMonumentsEnabled: Boolean
get() = Date().month == 8
/***
* Function to get the current WLM year
* It increments at the start of September in line with the other WLM functions
* (No consideration of locales for now)
* @param calendar
* @return
*/
fun getWikiLovesMonumentsYear(calendar: Calendar): Int {
var year = calendar[Calendar.YEAR]
if (calendar[Calendar.MONTH] < Calendar.SEPTEMBER) {
year -= 1
}
return year
}

View file

@ -0,0 +1,19 @@
package fr.free.nrw.commons.utils
import android.widget.TextView
import androidx.core.text.buildSpannedString
import androidx.core.text.underline
object UnderlineUtils {
// Convenience method for Java usages - remove when those classes are converted
@JvmStatic
fun setUnderlinedText(textView: TextView, stringResourceName: Int) {
textView.setUnderlinedText(stringResourceName)
}
}
fun TextView.setUnderlinedText(stringResourceName: Int) {
text = buildSpannedString {
underline { append(context.getString(stringResourceName)) }
}
}

View file

@ -0,0 +1,33 @@
package fr.free.nrw.commons.utils
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat
import fr.free.nrw.commons.R
import timber.log.Timber
/**
* Opens Custom Tab Activity with in-app browser for the specified URL.
* Launches intent for web URL
*/
fun handleWebUrl(context: Context, url: Uri) {
Timber.d("Launching web url %s", url.toString())
val color = CustomTabColorSchemeParams.Builder()
.setToolbarColor(ContextCompat.getColor(context, R.color.primaryColor))
.setSecondaryToolbarColor(ContextCompat.getColor(context, R.color.primaryDarkColor))
.build()
val customTabsIntent = CustomTabsIntent.Builder()
.setDefaultColorSchemeParams(color)
.setExitAnimations(
context, android.R.anim.slide_in_left, android.R.anim.slide_out_right
).build()
// Clear previous browser tasks, so that back/exit buttons work as intended.
customTabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
customTabsIntent.launchUrl(context, url)
}

View file

@ -196,13 +196,16 @@ class WikidataEditService @Inject constructor(
return wikidataClient.setClaim(claim, COMMONS_APP_TAG).blockingSingle() return wikidataClient.setClaim(claim, COMMONS_APP_TAG).blockingSingle()
} }
fun handleImageClaimResult(wikidataItem: WikidataItem, revisionId: Long?) { fun handleImageClaimResult(wikidataItem: WikidataItem, revisionId: Long?, p18WasSkipped: Boolean = false) {
if (revisionId != null) { if (revisionId != null) {
wikidataEditListener?.onSuccessfulWikidataEdit() wikidataEditListener?.onSuccessfulWikidataEdit()
showSuccessToast(wikidataItem.name) showSuccessToast(wikidataItem.name)
} else { } else if (!p18WasSkipped) {
Timber.d("Unable to make wiki data edit for entity %s", wikidataItem) Timber.d("Unable to make wiki data edit for entity %s", wikidataItem)
showLongToast(context, context.getString(R.string.wikidata_edit_failure)) showLongToast(context, context.getString(R.string.wikidata_edit_failure))
} else {
Timber.d("Wikidata edit skipped for entity %s because P18 already exists", wikidataItem)
// No error shown to user, as this is not a failure
} }
} }

View file

@ -341,7 +341,7 @@
<string name="deletion_reason_bad_for_my_privacy">Ek het besef dat dit sleg is vir my privaatheid</string> <string name="deletion_reason_bad_for_my_privacy">Ek het besef dat dit sleg is vir my privaatheid</string>
<string name="deletion_reason_no_longer_want_public">Ek het van plan verander, ek wil nie hê dit moet meer in die openbaar sigbaar wees nie</string> <string name="deletion_reason_no_longer_want_public">Ek het van plan verander, ek wil nie hê dit moet meer in die openbaar sigbaar wees nie</string>
<string name="deletion_reason_not_interesting">Jammer, hierdie foto is nie interessant vir \'n ensiklopedie nie</string> <string name="deletion_reason_not_interesting">Jammer, hierdie foto is nie interessant vir \'n ensiklopedie nie</string>
<string name="uploaded_by_myself">Opgelaai deur myself op %1$s, gebruik in %2$d artikel(s).</string> <string name="uploaded_by_myself" fuzzy="true">Opgelaai deur myself op %1$s, gebruik in %2$d artikel(s).</string>
<string name="no_uploads">Welkom by Commons!\n\nLaai u eerste media op deur op die byvoegknoppie te tik.</string> <string name="no_uploads">Welkom by Commons!\n\nLaai u eerste media op deur op die byvoegknoppie te tik.</string>
<string name="no_categories_selected">Geen kategorieë gekies nie</string> <string name="no_categories_selected">Geen kategorieë gekies nie</string>
<string name="no_categories_selected_warning_desc" fuzzy="true">Beelde sonder kategorieë is selde bruikbaar. Is u seker dat u wil indien sonder om kategorieë te kies?</string> <string name="no_categories_selected_warning_desc" fuzzy="true">Beelde sonder kategorieë is selde bruikbaar. Is u seker dat u wil indien sonder om kategorieë te kies?</string>

View file

@ -469,7 +469,7 @@
<string name="deletion_reason_bad_for_my_privacy">أدركت أنه سيئ لخصوصيتي</string> <string name="deletion_reason_bad_for_my_privacy">أدركت أنه سيئ لخصوصيتي</string>
<string name="deletion_reason_no_longer_want_public">لقد غيرت رأيي، ولا أريد أن يكون مرئيا للجميع بعد الآن</string> <string name="deletion_reason_no_longer_want_public">لقد غيرت رأيي، ولا أريد أن يكون مرئيا للجميع بعد الآن</string>
<string name="deletion_reason_not_interesting">آسف هذه الصورة ليست مثيرة للاهتمام لموسوعة</string> <string name="deletion_reason_not_interesting">آسف هذه الصورة ليست مثيرة للاهتمام لموسوعة</string>
<string name="uploaded_by_myself">رفعته بنفسي في %1$s، مستخدم في %2$d مقالة(ات).</string> <string name="uploaded_by_myself">تم تحميله بواسطة نفسي على %1$s، وتم استخدامه في %2$d مقالة على الأقل.</string>
<string name="no_uploads">مرحبا بك في كومنز! \n\nارفع الوسائط الأولى عن طريق النقر على زر الإضافة.</string> <string name="no_uploads">مرحبا بك في كومنز! \n\nارفع الوسائط الأولى عن طريق النقر على زر الإضافة.</string>
<string name="no_categories_selected">لا توجد تصنيفات مختارة</string> <string name="no_categories_selected">لا توجد تصنيفات مختارة</string>
<string name="no_categories_selected_warning_desc">نادرًا ما تكون الصور الخالية من التصنيفات قابلة للاستخدام، هل أنت متأكد أنك تريد الإرسال دون تحديد التصنيفات؟</string> <string name="no_categories_selected_warning_desc">نادرًا ما تكون الصور الخالية من التصنيفات قابلة للاستخدام، هل أنت متأكد أنك تريد الإرسال دون تحديد التصنيفات؟</string>
@ -642,6 +642,8 @@
<string name="title_for_media">وسائل الإعلام</string> <string name="title_for_media">وسائل الإعلام</string>
<string name="title_for_child_classes">تصنيف الأطفال</string> <string name="title_for_child_classes">تصنيف الأطفال</string>
<string name="title_for_parent_classes">تصنيف أولياء الأمور</string> <string name="title_for_parent_classes">تصنيف أولياء الأمور</string>
<string name="title_for_subcategories">الفئات الفرعية</string>
<string name="title_for_parent_categories">فئات الوالدين</string>
<string name="upload_nearby_place_found_title">تم العثور على مكان قريب</string> <string name="upload_nearby_place_found_title">تم العثور على مكان قريب</string>
<string name="upload_nearby_place_found_description_plural">هل هذه الصور لـ %1$s ؟</string> <string name="upload_nearby_place_found_description_plural">هل هذه الصور لـ %1$s ؟</string>
<string name="upload_nearby_place_found_description_singular">هل هذه صورة %1$s ؟</string> <string name="upload_nearby_place_found_description_singular">هل هذه صورة %1$s ؟</string>
@ -893,4 +895,5 @@
<string name="show_in_nearby">عرض في المناطق القريبة</string> <string name="show_in_nearby">عرض في المناطق القريبة</string>
<string name="image_tag_line_created_and_uploaded_by">تم الإنشاء والتحميل بواسطة: %1$s</string> <string name="image_tag_line_created_and_uploaded_by">تم الإنشاء والتحميل بواسطة: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">تم إنشاؤه بواسطة %1$s وتم تحميله بواسطة %2$s</string> <string name="image_tag_line_created_by_and_uploaded_by">تم إنشاؤه بواسطة %1$s وتم تحميله بواسطة %2$s</string>
<string name="nominated_for_deletion_btn">مرشح للحذف</string>
</resources> </resources>

View file

@ -395,7 +395,7 @@
<string name="deletion_reason_bad_for_my_privacy">Decatéme que ye malo pa la mio privacidá</string> <string name="deletion_reason_bad_for_my_privacy">Decatéme que ye malo pa la mio privacidá</string>
<string name="deletion_reason_no_longer_want_public">Cambié d\'opinión, nun quiero que siga siendo visible públicamente</string> <string name="deletion_reason_no_longer_want_public">Cambié d\'opinión, nun quiero que siga siendo visible públicamente</string>
<string name="deletion_reason_not_interesting">Sentímoslo, esta imaxe nun ye interesante pa una enciclopedia</string> <string name="deletion_reason_not_interesting">Sentímoslo, esta imaxe nun ye interesante pa una enciclopedia</string>
<string name="uploaded_by_myself">Xubíla yo mesmu\'l %1$s, usada en %2$d artículu(os).</string> <string name="uploaded_by_myself" fuzzy="true">Xubíla yo mesmu\'l %1$s, usada en %2$d artículu(os).</string>
<string name="no_uploads">¡Afáyate\'n Commons.\n\nCarga\'l to primer ficheru tocando nel botón amestar.</string> <string name="no_uploads">¡Afáyate\'n Commons.\n\nCarga\'l to primer ficheru tocando nel botón amestar.</string>
<string name="no_categories_selected">Nun hai categoríes seleicionaes</string> <string name="no_categories_selected">Nun hai categoríes seleicionaes</string>
<string name="no_categories_selected_warning_desc">Les imáxenes ensin categoríes raramente puen usase. ¿Seguro que quies siguir ensin escoyer categoría dala?</string> <string name="no_categories_selected_warning_desc">Les imáxenes ensin categoríes raramente puen usase. ¿Seguro que quies siguir ensin escoyer categoría dala?</string>

View file

@ -44,30 +44,63 @@
<item quantity="other">(%1$d)</item> <item quantity="other">(%1$d)</item>
</plurals> </plurals>
<string name="starting_uploads">Yükləmələrə Başlanılır</string> <string name="starting_uploads">Yükləmələrə Başlanılır</string>
<plurals name="starting_multiple_uploads">
<item quantity="one">%d yükləmə emal edilir</item>
<item quantity="other">%d yükləmə emal edilir</item>
</plurals>
<plurals name="multiple_uploads_title">
<item quantity="one">%d yükləmə</item>
<item quantity="other">%d yükləmə</item>
</plurals>
<plurals name="share_license_summary">
<item quantity="one">Bu şəkil %1$s lisenziyası altında yayımlanacaq</item>
<item quantity="other">Bu şəkillər %1$s lisenziyası altında yayımlanacaq</item>
</plurals>
<plurals name="upload_count_title">
<item quantity="one">%1$d yükləmə</item>
<item quantity="other">%1$d yükləmə</item>
</plurals>
<plurals name="receiving_shared_content">
<item quantity="one">Paylaşılan məzmun qəbul edilir. Şəklin emalı şəklin ölçüsündən və cihazınızdan asılı olaraq bir az vaxt apara bilər</item>
<item quantity="other">Paylaşılan məzmun qəbul edilir. Şəkillərin emalı şəklin ölçüsündən və cihazınızdan asılı olaraq bir az vaxt apara bilər</item>
</plurals>
<string name="navigation_item_explore">Kəşf et</string>
<string name="preference_category_appearance">Görünüş</string>
<string name="preference_category_general">Ümumi</string> <string name="preference_category_general">Ümumi</string>
<string name="preference_category_feedback">Rəy</string>
<string name="preference_category_privacy">Məxfilik</string> <string name="preference_category_privacy">Məxfilik</string>
<string name="app_name">Vikianbar</string> <string name="app_name">Vikianbar</string>
<string name="menu_settings">Tənzimləmələr</string> <string name="menu_settings">Tənzimləmələr</string>
<string name="intent_share_upload_label">Vikianbara yüklə</string>
<string name="upload_in_progress">Yükləmə davam edir</string>
<string name="username">İstifadəçi adı</string> <string name="username">İstifadəçi adı</string>
<string name="password">Parol</string> <string name="password">Parol</string>
<string name="login_credential">Commons Beta hesabınıza daxil olun</string>
<string name="login">Daxil ol</string> <string name="login">Daxil ol</string>
<string name="forgot_password">Şifrəni unutmusunuz?</string>
<string name="signup">Qeydiyyatdan keç</string> <string name="signup">Qeydiyyatdan keç</string>
<string name="logging_in_title">Giriş edilir</string> <string name="logging_in_title">Giriş edilir</string>
<string name="logging_in_message">Zəhmət olmasa, gözləyin…</string> <string name="logging_in_message">Zəhmət olmasa, gözləyin…</string>
<string name="updating_caption_title">Başlıqların və təsvirlərin yenilənməsi</string>
<string name="updating_caption_message">Zəhmət olmasa, gözləyin…</string>
<string name="login_success">Uğurlu giriş!</string> <string name="login_success">Uğurlu giriş!</string>
<string name="login_failed">Giriş baş tutmadı!</string> <string name="login_failed">Giriş baş tutmadı!</string>
<string name="upload_failed">Fayl tapılmadı. Xahiş edirik başqa bir fayl üzərində cəhd edin.</string> <string name="upload_failed">Fayl tapılmadı. Xahiş edirik başqa bir fayl üzərində cəhd edin.</string>
<string name="retry_limit_reached">Maksimum təkrar cəhd limitinə çatdınız! Zəhmət olmasa, yükləməni ləğv edin və yenidən cəhd edin</string> <string name="retry_limit_reached">Maksimum təkrar cəhd limitinə çatdınız! Zəhmət olmasa, yükləməni ləğv edin və yenidən cəhd edin</string>
<string name="unrestricted_battery_mode">Batareya optimallaşdırılması söndürülsün?</string> <string name="unrestricted_battery_mode">Batareya optimallaşdırılması söndürülsün?</string>
<string name="authentication_failed" fuzzy="true">Doğrulama alınmadı, xahiş edirəm yenidən daxil olun</string> <string name="suggest_unrestricted_mode">3-dən çox şəklin yüklənməsi batareyanın optimallaşdırılması söndürüldükdə daha yaxşı işləyir. Rahat yükləmə təcrübəsi üçün Vikianbar tətbiqi üçün batareyanın optimallaşdırılmasını parametrlərdən söndürün. \n\nBatareyanın optimallaşdırılmasını söndürmək üçün mümkün addımlar:\n\nAddım 1: Aşağıdakı \"Parametrlər\" düyməsinə toxunun.\n\nAddım 2: \"Optimallaşdırılmayıb\"dan \"Bütün proqramlar\"a keçin.\n\nAddım 3: \"Commons\" və ya \"fr.free.nrw.commons\" axtarın.\n\nAddım 4: \"Optimallaşdırma\"nı seçin.\n\nAddım 5: \'Bitti\' düyməsini basın.</string>
<string name="authentication_failed">Doğrulama alınmadı. Zəhmət olmasa, yenidən daxil olun</string>
<string name="uploading_started">Yükləmə başladı!</string> <string name="uploading_started">Yükləmə başladı!</string>
<string name="uploading_queued">Yükləmə növbədə (məhdud əlaqə rejimi aktivdir)</string>
<string name="upload_completed_notification_title">%1$s yükləndi!</string> <string name="upload_completed_notification_title">%1$s yükləndi!</string>
<string name="upload_completed_notification_text">Yükləmənizə baxmaq üçün toxunun</string> <string name="upload_completed_notification_text">Yükləmənizə baxmaq üçün toxunun</string>
<string name="upload_progress_notification_title_start" fuzzy="true">%1$s yüklənməsi başlanır</string> <string name="upload_progress_notification_title_start">Fayl yüklənir: %s</string>
<string name="upload_progress_notification_title_in_progress">%1$s yüklənir</string> <string name="upload_progress_notification_title_in_progress">%1$s yüklənir</string>
<string name="upload_progress_notification_title_finishing">%1$s yüklənməsi başa çatdı</string> <string name="upload_progress_notification_title_finishing">%1$s yüklənməsi başa çatdı</string>
<string name="upload_failed_notification_title" fuzzy="true">%1$s faylının yüklənməsi alınmadı</string> <string name="upload_failed_notification_title">%1$s yükləmək alınmadı</string>
<string name="upload_paused_notification_title">%1$s yüklənməsi dayandırıldı</string>
<string name="upload_failed_notification_subtitle">Baxmaq üçün toxun</string> <string name="upload_failed_notification_subtitle">Baxmaq üçün toxun</string>
<string name="upload_paused_notification_subtitle">Baxmaq üçün toxun</string>
<string name="title_activity_contributions">Son Yükləmələrim</string> <string name="title_activity_contributions">Son Yükləmələrim</string>
<string name="contribution_state_queued">Növbəyə alındı</string> <string name="contribution_state_queued">Növbəyə alındı</string>
<string name="contribution_state_failed">Uğursuz</string> <string name="contribution_state_failed">Uğursuz</string>
@ -77,49 +110,291 @@
<string name="menu_from_camera">Foto çək</string> <string name="menu_from_camera">Foto çək</string>
<string name="menu_nearby">Yaxınlıqdakılar</string> <string name="menu_nearby">Yaxınlıqdakılar</string>
<string name="provider_contributions">Yükləmələrim</string> <string name="provider_contributions">Yükləmələrim</string>
<string name="menu_copy_link">Keçidi kopiyala</string>
<string name="menu_link_copied">Link kopyalandı.</string>
<string name="menu_share">Paylaş</string> <string name="menu_share">Paylaş</string>
<string name="menu_view_file_page">Faylın səhifəsinə bax</string>
<string name="share_title_hint">Başlıq (Zəruri)</string> <string name="share_title_hint">Başlıq (Zəruri)</string>
<string name="add_caption_toast">Zəhmət olmasa, bu fayl üçün başlıq təqdim et</string>
<string name="share_description_hint">ıqlama</string> <string name="share_description_hint">ıqlama</string>
<string name="login_failed_network" fuzzy="true">Daxil olmaq olmur — şəbəkə xətası</string> <string name="share_caption_hint">Başlıq</string>
<string name="login_failed_network">Daxil olmaq mümkün deyil - şəbəkə xətası</string>
<string name="login_failed_throttled">Çox sayda uğursuz daxil olma. Xahiş edirik bir neçə dəqiqə sonra yenidən cəhd edin.</string> <string name="login_failed_throttled">Çox sayda uğursuz daxil olma. Xahiş edirik bir neçə dəqiqə sonra yenidən cəhd edin.</string>
<string name="login_failed_blocked">Bağışlayın, bu istifadəçi Vikianbardan bloklanıb</string> <string name="login_failed_blocked">Bağışlayın, bu istifadəçi Vikianbardan bloklanıb</string>
<string name="login_failed_2fa_needed">Siz iki faktorlu autentifikasiya kodunuzu təqdim etməlisiniz.</string> <string name="login_failed_2fa_needed">Siz iki faktorlu autentifikasiya kodunuzu təqdim etməlisiniz.</string>
<string name="login_failed_generic" fuzzy="true">Daxil olma uğursuz oldu</string> <string name="login_failed_email_auth_needed">E-poçt ünvanınıza giriş doğrulama kodu göndərildi. Daxil olmaq üçün kodu daxil edin.</string>
<string name="login_failed_generic">Daxil olma uğursuz oldu</string>
<string name="share_upload_button">Yüklə</string> <string name="share_upload_button">Yüklə</string>
<string name="multiple_share_base_title">Bu dəsti adlandırın</string> <string name="multiple_share_base_title">Bu dəsti adlandırın</string>
<string name="provider_modifications">Dəyişikliklər</string> <string name="provider_modifications">Dəyişikliklər</string>
<string name="menu_upload_single">Yüklə</string> <string name="menu_upload_single">Yüklə</string>
<string name="categories_search_text_hint">Kateqoriyalarda axtar</string> <string name="categories_search_text_hint">Kateqoriyalarda axtar</string>
<string name="depicts_search_text_hint">Medianızın təsvir etdiyi elementləri axtarın (dağ, Tac Mahal və s.)</string>
<string name="menu_save_categories">Yadda saxla</string> <string name="menu_save_categories">Yadda saxla</string>
<string name="refresh_button">Yenilə</string> <string name="refresh_button">Yenilə</string>
<string name="display_list_button">Siyahı</string> <string name="display_list_button">Siyahı</string>
<string name="contributions_subtitle_zero">(Hələ yükləmə yoxdur)</string> <string name="contributions_subtitle_zero">(Hələ yükləmə yoxdur)</string>
<string name="categories_not_found">%1$s axtarışına uyğun kateqoriya tapılmadı</string> <string name="categories_not_found">%1$s axtarışına uyğun kateqoriya tapılmadı</string>
<string name="depictions_not_found">%1$s uyğun heç bir Vikidata elementi tapılmadı</string>
<string name="no_child_classes">%1$s alt sinifləri yoxdur</string>
<string name="no_parent_classes">%1$s üst sinfi yoxdur</string>
<string name="categories_skip_explanation">Şəkillərinizi Vikianbarda daha tapıla bilən etmək üçün kateqoriyalar əlavə edin.\nKateqoriyalar əlavə etmək üçün yazmağa başlayın.</string>
<string name="categories_activity_title">Kateqoriyalar</string> <string name="categories_activity_title">Kateqoriyalar</string>
<string name="title_activity_settings">Nizamlamalar</string> <string name="title_activity_settings">Nizamlamalar</string>
<string name="title_activity_signup">Qeydiyyatdan keç</string> <string name="title_activity_signup">Qeydiyyatdan keç</string>
<string name="title_activity_featured_images">Seçilmiş şəkillər</string> <string name="title_activity_featured_images">Seçilmiş şəkillər</string>
<string name="title_activity_custom_selector">Xüsusi Seçici</string>
<string name="title_activity_category_details">Kateqoriya</string> <string name="title_activity_category_details">Kateqoriya</string>
<string name="title_activity_review">Yoxlanış</string>
<string name="menu_about">Haqqında</string> <string name="menu_about">Haqqında</string>
<string name="about_license">Vikianbar proqramı Vikimedia icmasının qrant alanları və könüllüləri tərəfindən yaradılmış və dəstəklənən açıq mənbəli proqramdır. Vikimedia Fondu proqramın yaradılması, inkişafı və ya texniki xidmətində iştirak etmir.</string>
<string name="about_improve">Xəta hesabatları və təkliflər üçün yeni &lt;a href=\"%1$s\"&gt;GitHub sorğusu&lt;/a&gt; yaradın.</string>
<string name="about_privacy_policy">Məxfilik siyasəti</string> <string name="about_privacy_policy">Məxfilik siyasəti</string>
<string name="about_credits">Töhfə verənlər</string>
<string name="title_activity_about">Haqqında</string> <string name="title_activity_about">Haqqında</string>
<string name="menu_feedback">Rəy göndər (e-poçt vasitəsilə)</string>
<string name="no_email_client">Heç bir e-poçt tətbiqi quraşdırılmayıb</string>
<string name="provider_categories">Son istifadə olunan kateqoriyalar</string>
<string name="waiting_first_sync">İlk sinxronizasiya gözlənilir…</string>
<string name="no_uploads_yet">Siz hələ heç bir şəkil yükləməmisiniz.</string>
<string name="menu_retry_upload">Yenidən cəhd edin</string> <string name="menu_retry_upload">Yenidən cəhd edin</string>
<string name="menu_cancel_upload">İmtina</string>
<string name="media_upload_policy">Bu şəkli yükləməklə bildirirəm ki, bu mənim şəxsi işimdir, onda müəllif hüququ ilə qorunan material və ya selfilər yoxdur və &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Policies_and_guidelines\"&gt;Vikianbar qaydalarına&lt;/a&gt; riayət edir.</string>
<string name="menu_download">Endir</string> <string name="menu_download">Endir</string>
<string name="preference_license">Defolt lisenziya</string>
<string name="use_previous">Əvvəlki başlıq və təsvirdən istifadə et</string>
<string name="preference_theme">Tema</string>
<string name="license_name_cc_by_3_0">CC BY 3.0</string> <string name="license_name_cc_by_3_0">CC BY 3.0</string>
<string name="tutorial_1_text">Vikianbar Vikipediyada istifadə olunan şəkillərin əksəriyyətinə ev sahibliyi edir.</string>
<string name="tutorial_1_subtext">Şəkilləriniz bütün dünyada insanları maarifləndirməyə kömək edir!</string>
<string name="tutorial_2_text">Tamamilə özünüz tərəfindən çəkilmiş və ya yaradılmış şəkilləri yükləyin:</string>
<string name="tutorial_2_subtext_1">Təbii obyektlər (çiçəklər, heyvanlar, dağlar)</string>
<string name="tutorial_2_subtext_2">Faydalı obyektlər (velosipedlər, qatar stansiyaları)</string>
<string name="tutorial_2_subtext_3">Məşhur insanlar (icra başçınız, tanış olduğunuz olimpiya idmançıları)</string>
<string name="tutorial_3_text">Zəhmət olmasa, YÜKLƏMƏYİN:</string>
<string name="tutorial_3_subtext_1">Selfi və ya dostlarınızın şəkilləri</string>
<string name="tutorial_3_subtext_2">İnternetdə tapdığınız şəkillər</string>
<string name="tutorial_3_subtext_3">Özəl proqramların ekran görüntüləri</string>
<string name="tutorial_4_text">Yükləmə nümunəsi:</string>
<string name="tutorial_4_subtext_1">Başlıq: Sidney Opera Evi</string>
<string name="tutorial_4_subtext_2">Təsvir: Sidney Opera Evinin körfəzdən görünüşü</string>
<string name="tutorial_4_subtext_3">Kateqoriyalar: Sidney Opera Evi Qərb istiqamətindən, Sidney Opera Evinin uzaqdan mənzərələri</string>
<string name="welcome_wikipedia_text">Şəkilləriniz ilə töhfə verin. Vikipediya məqalələrinin canlanmasına kömək edin!</string>
<string name="welcome_wikipedia_subtext">Vikipediyadakı şəkillər Vikianbardan götürülüb.</string>
<string name="welcome_copyright_text">Şəkilləriniz bütün dünyada insanları maarifləndirməyə kömək edir.</string>
<string name="welcome_copyright_subtext">İnternetdən tapdığınız müəllif hüquqları ilə qorunan materialları, eləcə də afişaların, kitab üzlüklərinin və s. şəkillərini yükləməkdən çəkinin.</string>
<string name="welcome_final_text">Sizcə bunu başa düşdünüz?</string>
<string name="welcome_final_button_text">Bəli!</string>
<string name="welcome_help_button_text">Əlavə məlumat</string> <string name="welcome_help_button_text">Əlavə məlumat</string>
<string name="detail_panel_cats_label">Kateqoriyalar</string> <string name="detail_panel_cats_label">Kateqoriyalar</string>
<string name="detail_panel_cats_loading">Yüklənir...</string> <string name="detail_panel_cats_loading">Yüklənir...</string>
<string name="detail_panel_cats_none">Heç biri seçilməmişdir</string> <string name="detail_panel_cats_none">Heç biri seçilməmişdir</string>
<string name="detail_caption_empty">Başlıq yoxdur</string>
<string name="detail_description_empty">Təsvir yoxdur</string>
<string name="detail_discussion_empty">Müzakirə yoxdur</string>
<string name="detail_license_empty">Naməlum lisenziya</string> <string name="detail_license_empty">Naməlum lisenziya</string>
<string name="menu_refresh">Yenilə</string> <string name="menu_refresh">Yenilə</string>
<string name="storage_permission_title">Yaddaşa giriş icazəsi tələb olunur</string>
<string name="read_storage_permission_rationale">Tələb olunan icazə: Xarici yaddaşı oxumaq. Bu olmadan proqram qalereyanıza daxil ola bilməz.</string>
<string name="write_storage_permission_rationale">Tələb olunan icazə: Xarici yaddaşa yazmaq. Bu olmadan proqram kameranıza/qalereyanıza daxil ola bilməz.</string>
<string name="location_permission_title">Məkan icazəsi tələb olunur</string>
<string name="in_app_camera_location_permission_title">Tətbiqdaxili çəkilişlər üçün məkanı qeyd et</string>
<string name="in_app_camera_location_switch_pref_summary">Cihaz kamerası onu qeyd etmədiyi halda, məkanı tətbiqdaxili çəkilişlərlə əlavə etmək üçün bunu aktiv edin</string>
<string name="ok">Oldu</string>
<string name="warning">Xəbərdarlıq</string>
<string name="duplicate_file_name">Dublikat fayl adı tapıldı</string>
<string name="upload">Yüklə</string>
<string name="yes">Bəli</string> <string name="yes">Bəli</string>
<string name="no">Xeyr</string> <string name="no">Xeyr</string>
<string name="media_detail_caption">Başlıq</string>
<string name="media_detail_title">Başlıq</string> <string name="media_detail_title">Başlıq</string>
<string name="media_detail_depiction">Təsvirlər</string>
<string name="media_detail_description">Təsvir</string>
<string name="media_detail_discussion">Müzakirə</string> <string name="media_detail_discussion">Müzakirə</string>
<string name="media_detail_author">Müəllif</string> <string name="media_detail_author">Müəllif</string>
<string name="media_detail_uploaded_date">Yüklənmə tarixi</string>
<string name="media_detail_license">Lisenziya</string> <string name="media_detail_license">Lisenziya</string>
<string name="media_detail_coordinates">Koordinatlar</string>
<string name="media_detail_coordinates_empty">Heç biri göstərilməyib</string>
<string name="become_a_tester_title">Beta Tester ol</string>
<string name="become_a_tester_description">Google Play-də beta kanalımıza qoşulun və yeni funksiyalara və xəta həllərinə erkən giriş əldə edin</string>
<string name="_2fa_code">2FA kodu</string>
<string name="email_auth_code">E-poçt doğrulama kodu</string>
<string name="logout_verification">Həqiqətən çıxış etmək istəyirsiniz?</string>
<string name="mediaimage_failed">Media şəkli uğursuz oldu</string>
<string name="no_subcategory_found">Heç bir alt kateqoriya tapılmadı</string>
<string name="no_parentcategory_found">Heç bir üst kateqoriya tapılmadı</string>
<string name="welcome_image_mount_zao">Zao dağı</string>
<string name="welcome_image_llamas">Lamalar</string>
<string name="welcome_image_rainbow_bridge">Göy qurşağı körpüsü</string>
<string name="welcome_image_tulip">Lalə</string>
<string name="welcome_image_welcome_wikipedia">Vikipediyaya xoş gəlmisiniz</string>
<string name="welcome_image_welcome_copyright">Müəlliflik hüquqlarına xoş gəlmisiniz</string>
<string name="welcome_image_sydney_opera_house">Sidney Opera Evi</string>
<string name="cancel">İmtina</string>
<string name="navigation_drawer_open"></string>
<string name="navigation_drawer_close">Bağla</string>
<string name="navigation_item_home">Ana səhifə</string>
<string name="navigation_item_upload">Yüklə</string>
<string name="navigation_item_nearby">Yaxınlıqdakılar</string>
<string name="navigation_item_about">Haqqında</string>
<string name="navigation_item_settings">Parametrlər</string>
<string name="navigation_item_feedback">Rəy</string>
<string name="navigation_item_feedback_github">GitHub vasitəsilə rəy</string>
<string name="navigation_item_logout">Çıxış</string>
<string name="navigation_item_info">Təlimat</string>
<string name="navigation_item_notification">Bildirişlər</string>
<string name="navigation_item_review">Yoxla</string>
<string name="no_description_found">təsvir tapılmadı</string>
<string name="nearby_info_menu_commons_article">Commons fayl səhifəsi</string>
<string name="nearby_info_menu_wikidata_article">Vikidata elementi</string>
<string name="nearby_info_menu_wikipedia_article">Vikipediya məqaləsi</string>
<string name="description_info">Zəhmət olmasa, medianı mümkün qədər təsvir edin: Harada çəkilib? Nəyi təsvir edir? Kontekst nədir? Obyektləri və ya şəxsləri təsvir edin. Asanlıqla təxmin edilə bilməyən məlumatları, məsələn, bir mənzərədirsə, günün saatını qeyd edin. Əgər media qeyri-adi bir şey göstərirsə, zəhmət olmasa, onu izah edin.</string>
<string name="caption_info">Zəhmət olmasa şəklin qısa təsvirini yazın. İlk başlıq şəkil üçün Başlıq kimi istifadə olunacaq. 255 simvolla məhdudlaşır.</string>
<string name="upload_problem_exist">Bu şəkil ilə bağlı potensial problemlər:</string>
<string name="upload_problem_image_dark">Şəkil çox qaranlıqdır.</string>
<string name="upload_problem_image_blurry">Şəkil bulanıqdır.</string>
<string name="upload_problem_image_duplicate">Şəkil artıq Vikianbarda var.</string>
<string name="upload_problem_different_geolocation">Bu şəkil başqa yerdə çəkilib.</string>
<string name="upload_problem_fbmd">Zəhmət olmasa, yalnız özünüz çəkdiyiniz şəkilləri yükləyin. Başqalarının Facebook hesablarında tapdığınız şəkilləri yükləməyin.</string>
<string name="upload_problem_do_you_continue">Hələ də bu şəkli yükləmək istəyirsiniz?</string>
<string name="upload_connection_error_alert_title">Bağlantı xətası</string>
<string name="upload_connection_error_alert_detail">Yükləmə prosesi aktiv internetə çıxış tələb edir. Şəbəkə bağlantınızı yoxlayın.</string>
<string name="upload_problem_image">Şəkildə tapılan problemlər</string>
<string name="internet_downloaded">Zəhmət olmasa, yalnız özünüz çəkdiyiniz şəkilləri yükləyin. İnternetdən tapdığınız şəkilləri yükləməyin.</string>
<string name="use_external_storage">Tətbiqdaxili kadrları yadda saxla</string>
<string name="use_external_storage_summary">Tətbiqdaxili kamera ilə çəkilmiş şəkilləri cihazın yaddaşında saxla</string>
<string name="login_to_your_account">Hesabınıza daxil olun</string>
<string name="send_log_file">Jurnal faylını göndərin</string>
<string name="send_log_file_description">Proqramla bağlı problemlərin aradan qaldırılmasına kömək etmək üçün jurnal faylını tərtibatçılara e-poçt vasitəsilə göndərin. Qeyd: jurnallar potensial olaraq şəxsi məlumatları ehtiva edə bilər</string>
<string name="no_web_browser">URL-i açmaq üçün heç bir veb brauzer tapılmadı</string>
<string name="null_url">Xəta! URL tapılmadı</string>
<string name="nominate_deletion">Silinməyə namizəd göstər</string>
<string name="nominated_for_deletion">Bu şəkil silinməyə namizəddir.</string>
<string name="nominated_see_more">Ətraflı məlumat üçün veb səhifəsinə bax</string>
<string name="skip_login">Ötür</string>
<string name="navigation_item_login">Daxil ol</string>
<string name="skip_login_title">Daxil olma mərhələsini keçmək istədiyinizə əminsiniz?</string>
<string name="skip_login_message">Gələcəkdə şəkilləri yükləmək üçün daxil olmalısınız.</string>
<string name="login_alert_message">Bu funksiyadan istifadə etmək üçün zəhmət olmasa daxil olun</string>
<string name="copy_wikicode">Vikimətni mübadilə buferinə köçür</string>
<string name="wikicode_copied">Vikimətn mübadilə buferinə köçürüldü</string>
<string name="nearby_location_not_available">Yaxınlıqdakılar düzgün işləməyə bilər, məkan əlçatan deyil.</string>
<string name="nearby_showing_pins_offline">İnternet əlçatan deyil. Yalnız keşlənmiş yerlər göstərilir.</string>
<string name="upload_location_access_denied">Məkan girişi rədd edildi. Bu funksiyadan istifadə etmək üçün yerinizi manual təyin edin.</string>
<string name="location_permission_rationale_nearby">Yaxınlıqdakı yerlərin siyahısını göstərmək üçün icazə tələb olunur</string>
<string name="location_permission_rationale_explore">Yaxınlıqdakı şəkillərin siyahısını göstərmək üçün icazə tələb olunur</string>
<string name="nearby_directions">İstiqamətlər</string>
<string name="nearby_wikidata">Vikidata</string> <string name="nearby_wikidata">Vikidata</string>
<string name="nearby_wikipedia">Vikipediya</string> <string name="nearby_wikipedia">Vikipediya</string>
<string name="nearby_commons">Vikianbar</string>
<string name="about_rate_us">Bizi qiymətləndir</string>
<string name="about_faq">TSS</string>
<string name="user_guide">İstifadəçi təlimatı</string>
<string name="welcome_skip_button">Təlimatı ötür</string>
<string name="no_internet">İnternet əlçatan deyil</string>
<string name="error_notifications">Bildirişləri əldə edərkən xəta baş verdi</string>
<string name="error_review">Şəkli nəzərdən keçirmək üçün gətirilərkən xəta baş verdi. Yenidən cəhd etmək üçün yeniləmə düyməsini basın.</string>
<string name="no_notifications">Heç bir bildiriş tapılmadı</string>
<string name="about_translate">Tərcümə et</string>
<string name="about_translate_title">Dillər</string>
<string name="about_translate_message">Tərcümələri təqdim etmək istədiyiniz dili seçin</string>
<string name="about_translate_proceed">Davam et</string>
<string name="about_translate_cancel">İmtina</string>
<string name="retry">Yenidən cəhd et</string>
<string name="showcase_view_whole_nearby_activity">Bunlar sizə yaxın yerlərdir və onların Vikipediya məqalələrini təsvir etmək üçün şəkillərə ehtiyac duyurlar.\n\n\'BU SAHƏDƏ AXTAR\' düyməsinə klikləməklə, xəritə kilidləyib həmin məkan ətrafında yaxınlıqda axtarış başlaya bilərsiniz.</string>
<string name="showcase_view_needs_photo">Bu yerə şəkil lazımdır.</string>
<string name="showcase_view_has_photo">Bu yerin artıq şəkli var.</string>
<string name="showcase_view_no_longer_exists">Bu yer artıq mövcud deyil.</string>
<string name="no_images_found">Şəkil tapılmadı!</string>
<string name="error_loading_images">Şəkillər yüklənərkən xəta baş verdi.</string>
<string name="image_uploaded_by">%1$s tərəfindən yüklənilib</string>
<string name="block_notification_title">Bloklanıb</string>
<string name="block_notification">Sizə Vikianbarı redaktə etmək qadağan edilib</string>
<string name="app_widget_heading">Günün Şəkli</string>
<string name="menu_search_button">Axtar</string>
<string name="search_commons">Vikianbarda axtar</string>
<string name="title_activity_search">Axtar</string>
<string name="search_recent_header">Son axtarışlar:</string>
<string name="provider_searches">Bu yaxınlarda axtarılanlar</string>
<string name="provider_recent_languages">Son dil sorğuları</string>
<string name="error_loading_categories">Kateqoriyalar yüklənərkən xəta baş verdi.</string>
<string name="error_loading_depictions">Təsvirləri yükləyərkən xəta baş verdi.</string>
<string name="search_tab_title_media">Media</string>
<string name="search_tab_title_categories">Kateqoriyalar</string>
<string name="search_tab_title_depictions">Elementlər</string>
<string name="explore_tab_title_featured">Seçilmiş</string>
<string name="explore_tab_title_mobile">Mobil tətbiq vasitəsilə yüklənib</string>
<string name="explore_tab_title_map">Xəritə</string>
<string name="successful_wikidata_edit">Şəkil Vikidatada %1$s elementinə əlavə edildi</string>
<string name="wikidata_edit_failure">Müvafiq Vikidata obyektini yeniləmək alınmadı!</string>
<string name="menu_set_wallpaper">Divar kağızı kimi təyin et</string>
<string name="wallpaper_set_successfully">Divar kağızı uğurla təyin edildi!</string>
<string name="quiz">Sorğu</string>
<string name="quiz_question_string">Bu şəkli yükləmək olar?</string>
<string name="question">Sual</string>
<string name="result">Nəticə</string>
<string name="quiz_back_button">Silinməyi tələb edilən şəkilləri yükləməyə davam etsəniz, hesabınız blok olunacaq. Sorğunu bitirmək istədiyinizə əminsiniz?</string>
<string name="quiz_alert_message">Yüklədiyiniz şəkillərin %1$s+ ədədi silinib. Silinməyi tələb edilən şəkilləri yükləməyə davam etsəniz, hesabınız blok olunacaq.\n\nTəlimata yenidən baxmaq və sonra hansı növ şəkilləri yükləməli və ya yükləməməli olduğunuzu öyrənməyə kömək etmək üçün testdən keçmək istəyirsiniz?</string>
<string name="selfie_answer">Selfielərin o qədər də məlumatlandırıcı dəyəri yoxdur. Haqqınızda Vikipediya məqaləsi yoxdursa, zəhmət olmasa, şəklinizi yükləməyin.</string>
<string name="taj_mahal_answer">Abidələrin və mənzərələrin şəkillərini əksər ölkələrdə yükləmək olar. Nəzərə alın ki, xaricdəki müvəqqəti incəsənət abidələri tez-tez müəllif hüquqları ilə qorunur və yükləmək düzgün deyil.</string>
<string name="screenshot_answer">Veb saytların skrinşotları törəmə əsərlər hesab edilir və veb-saytdakı müəllif hüququna tabedir. Bunlar müəllifin icazəsindən sonra istifadə edilə bilər. Belə icazə olmadan, onların işi əsasında yaratdığınız hər hansı əsər qanuni olaraq orijinal müəllifə məxsus lisenziyasız nüsxə sayılır.</string>
<string name="blurry_image_answer">Vikianbarın məqsədlərindən biri keyfiyyətli şəkillər toplamaqdır. Ona görə də bulanıq şəkillər yüklənməməlidir. Həmişə yaxşııqlandırma ilə gözəl şəkillər çəkməyə çalışın.</string>
<string name="construction_event_answer">Texnologiya və ya mədəniyyəti təsvir edən şəkillər üçün Vikianbarda həmişə yer var.</string>
<string name="congratulatory_message_quiz">Cavabların %1$s ədədi düzgündür. Təbriklər!</string>
<string name="warning_for_no_answer">Suala cavab vermək üçün iki variantdan birini seçin</string>
<string name="user_not_logged_in">Giriş müddəti bitib. Zəhmət olmasa, yenidən daxil olun.</string>
<string name="quiz_result_share_message">Bunu dostlarınızla paylaşın!</string>
<string name="continue_message">Davam et</string>
<string name="correct">Düzgün Cavab</string>
<string name="wrong">Yanlış Cavab</string>
<string name="quiz_screenshot_question">Bu skrinşotu yükləmək olar?</string>
<string name="share_app_title">Proqramı paylaş</string>
<string name="rotate">Fırlat</string>
<string name="error_fetching_nearby_places">Yaxınlıqdakı yerləri yükləmək mümkün olmadı</string>
<string name="no_pictures_in_this_area">Bu ərazidə şəkillər yoxdur</string>
<string name="no_nearby_places_around">Yaxınlıqda yer tapılmadı</string>
<string name="error_fetching_nearby_monuments">Yaxınlıqdakı abidələri əldə edərkən xəta baş verdi.</string>
<string name="no_recent_searches">Son axtarışlar yoxdur</string>
<string name="delete_recent_searches_dialog">Axtarış tarixçəsini silmək istədiyindən əminsiniz?</string>
<string name="cancel_upload_dialog">Bu yükləməni ləğv etmək istədiyinizə əminsiniz?</string>
<string name="delete_search_dialog">Bu axtarışı silmək istəyirsiniz?</string>
<string name="search_history_deleted">Axtarış tarixçəsi silindi</string>
<string name="nominate_delete">Silinməyə namizəd göstər</string>
<string name="delete">Sil</string>
<string name="Achievements">Nailiyyətlər</string>
<string name="Profile">Profil</string>
<string name="badges">Rozetlər</string>
<string name="statistics">Statistika</string>
<string name="statistics_thanks">Qəbul edilən təşəkkürlər</string>
<string name="statistics_featured">Seçilmiş şəkillər</string>
<string name="statistics_wikidata_edits">\"Yaxınlıqdakı yerlər\" vasitəsilə şəkillər</string>
<string name="level">Səviyyə %d</string>
<string name="profileLevel">%s (Səviyyə %s)</string>
<string name="images_uploaded">Yüklənən şəkillər</string>
<string name="image_reverts">Geri qaytarılan şəkillər</string>
<string name="images_used_by_wiki">İstifadə olunan şəkillər</string>
<string name="achievements_share_message">Nailiyyətlərinizi dostlarınızla paylaşın!</string>
<string name="achievements_info_message">Bu tələbləri yerinə yetirdikcə səviyyəniz yüksəlir. \"Statistika\" bölməsindəki elementlər sizin səviyyənizi nəzərə almır.</string>
<string name="achievements_revert_limit_message">minimum tələb olunur:</string>
<string name="images_uploaded_explanation">İstənilən yükləmə proqramı vasitəsilə Vikianbara yüklədiyiniz şəkillərin sayı</string>
<string name="images_reverted_explanation">Vikianbara yüklədiyiniz və silinməyən şəkillərin faizi</string>
<string name="images_used_explanation">Vikianbara yüklədiyiniz və Vikimedia məqalələrində istifadə olunan şəkillərin sayı</string>
<string name="error_occurred">Xəta baş verdi!</string>
<string name="notifications_channel_name_all">Vikianbar bildirişi</string>
<string name="preference_author_name_toggle">Fərdi müəllif adından istifadə et</string>
<string name="preference_author_name_toggle_summary">Fotoşəkilləri yükləyərkən istifadəçi adınız əvəzinə fərdi müəllif adından istifadə edin</string>
<string name="preference_author_name">Fərdi müəllif adı</string>
<string name="contributions_fragment">Töhfələr</string>
<string name="nearby_fragment">Yaxınlıqdakılar</string>
<string name="notifications">Bildirişlər</string>
<string name="read_notifications">Bildirişlər (oxunmuş)</string>
<string name="display_nearby_notification">Yaxınlıqdakı bildirişini göstər</string>
<string name="display_nearby_notification_summary">Şəkillərə ehtiyacı olan ən yaxın yerlər üçün tətbiqdaxili bildiriş göstərin</string>
<string name="list_sheet">Siyahı</string>
<string name="storage_permission">Yaddaş icazəsi</string>
<string name="write_storage_permission_rationale_for_image_share">Şəkilləri yükləmək üçün cihazınızın xarici yaddaşına giriş icazəsi lazımdır.</string>
<string name="nearby_notification_dismiss_message">Artıq şəkillərə ehtiyacı olan ən yaxın yeri görməyəcəksiniz. Bununla belə, istəyirsinizsə, bu bildirişi Parametrlərdə yenidən aktivləşdirə bilərsiniz.</string>
<string name="send_thank_success_title">Təşəkkür uğurla göndərildi</string> <string name="send_thank_success_title">Təşəkkür uğurla göndərildi</string>
<string name="send_thank_failure_message">Təşəkkür göndərilə bilmədi %1$s</string> <string name="send_thank_failure_message">Təşəkkür göndərilə bilmədi %1$s</string>
<string name="send_thank_failure_title">Təşəkkür göndərilir: Xəta</string> <string name="send_thank_failure_title">Təşəkkür göndərilir: Xəta</string>

View file

@ -394,7 +394,7 @@
<string name="deletion_reason_bad_for_my_privacy">Shvatio/la sam da je loša za moju privatnost</string> <string name="deletion_reason_bad_for_my_privacy">Shvatio/la sam da je loša za moju privatnost</string>
<string name="deletion_reason_no_longer_want_public">Promenio/la sam mišljenje, ne želim da više javno budu vidljive</string> <string name="deletion_reason_no_longer_want_public">Promenio/la sam mišljenje, ne želim da više javno budu vidljive</string>
<string name="deletion_reason_not_interesting">Ova slika nije zanimljiva za enciklopediju</string> <string name="deletion_reason_not_interesting">Ova slika nije zanimljiva za enciklopediju</string>
<string name="uploaded_by_myself">Otpremio/la sam na %1$s, koristi se u članku/cima — %2$d.</string> <string name="uploaded_by_myself" fuzzy="true">Otpremio/la sam na %1$s, koristi se u članku/cima — %2$d.</string>
<string name="no_uploads">Dobro došli na Ostavu!\n\nOtpremite prve medije dodirom dugmeta za dodavanje.</string> <string name="no_uploads">Dobro došli na Ostavu!\n\nOtpremite prve medije dodirom dugmeta za dodavanje.</string>
<string name="no_categories_selected">Kategorije nisu izabrane</string> <string name="no_categories_selected">Kategorije nisu izabrane</string>
<string name="no_categories_selected_warning_desc">Slike bez kategorija retko su upotrebljive. Zaista želite da nastavite bez izbora kategorija?</string> <string name="no_categories_selected_warning_desc">Slike bez kategorija retko su upotrebljive. Zaista želite da nastavite bez izbora kategorija?</string>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Authors: <!-- Authors:
* Farorud
* Ibrahim * Ibrahim
* ToJack * ToJack
* Vashgird * Vashgird
@ -102,7 +103,7 @@
<string name="navigation_item_logout">Баромад</string> <string name="navigation_item_logout">Баромад</string>
<string name="navigation_item_notification">Огоҳиҳо</string> <string name="navigation_item_notification">Огоҳиҳо</string>
<string name="navigation_item_review">Тафтиш</string> <string name="navigation_item_review">Тафтиш</string>
<string name="nearby_info_menu_wikidata_article">Унсури Викидода</string> <string name="nearby_info_menu_wikidata_article">Элементи Викидода</string>
<string name="navigation_item_login">Вуруд</string> <string name="navigation_item_login">Вуруд</string>
<string name="nearby_directions">Ҷиҳат</string> <string name="nearby_directions">Ҷиҳат</string>
<string name="nearby_wikidata">Викидода</string> <string name="nearby_wikidata">Викидода</string>

View file

@ -12,6 +12,7 @@
* Mohammed Galib Hasan * Mohammed Galib Hasan
* Muktogayn * Muktogayn
* NahidHossain * NahidHossain
* Nokib Sarkar
* R4356th * R4356th
* Rasal Lia * Rasal Lia
* Sankarshan * Sankarshan
@ -32,6 +33,7 @@
<string name="commons_github">কমন্স গিটহাব উৎস কোড</string> <string name="commons_github">কমন্স গিটহাব উৎস কোড</string>
<string name="commons_logo">কমন্সের লোগো</string> <string name="commons_logo">কমন্সের লোগো</string>
<string name="commons_website">কমন্স ওয়েবসাইট</string> <string name="commons_website">কমন্স ওয়েবসাইট</string>
<string name="exit_location_picker">লোকেশন পিকার থেকে বেরিয়ে আসুন</string>
<string name="submit">জমা দিন</string> <string name="submit">জমা দিন</string>
<string name="add_another_description">আরেকটি বিবরণ যোগ করুন</string> <string name="add_another_description">আরেকটি বিবরণ যোগ করুন</string>
<string name="add_new_contribution">নতুন অবদান যোগ করুন</string> <string name="add_new_contribution">নতুন অবদান যোগ করুন</string>
@ -44,6 +46,9 @@
<string name="show_captions_description">বিবরণ</string> <string name="show_captions_description">বিবরণ</string>
<string name="nearby_row_image">চিত্র</string> <string name="nearby_row_image">চিত্র</string>
<string name="nearby_all">সব</string> <string name="nearby_all">সব</string>
<string name="nearby_filter_toggle">টগল আপ</string>
<string name="nearby_filter_search">অনুসন্ধান দৃশ্য</string>
<string name="nearby_filter_state">স্থানের অবস্থা</string>
<string name="appwidget_img">আজকের চিত্র</string> <string name="appwidget_img">আজকের চিত্র</string>
<plurals name="uploads_pending_notification_indicator"> <plurals name="uploads_pending_notification_indicator">
<item quantity="one">%1$dটি ফাইল আপলোড হচ্ছে</item> <item quantity="one">%1$dটি ফাইল আপলোড হচ্ছে</item>
@ -70,6 +75,10 @@
<item quantity="one">%1$dটি আপলোড</item> <item quantity="one">%1$dটি আপলোড</item>
<item quantity="other">%1$dটি আপলোড</item> <item quantity="other">%1$dটি আপলোড</item>
</plurals> </plurals>
<plurals name="receiving_shared_content">
<item quantity="one">শেয়ার করা কন্টেন্ট পাওয়া। ছবির আকার এবং আপনার ডিভাইসের উপর নির্ভর করে ছবিটি প্রক্রিয়াকরণে কিছুটা সময় লাগতে পারে</item>
<item quantity="other">শেয়ার করা কন্টেন্ট পাওয়া। ছবির আকার এবং আপনার ডিভাইসের উপর নির্ভর করে ছবি প্রক্রিয়াকরণে কিছুটা সময় লাগতে পারে</item>
</plurals>
<string name="navigation_item_explore">অন্বেষণ</string> <string name="navigation_item_explore">অন্বেষণ</string>
<string name="preference_category_appearance">অবয়ব</string> <string name="preference_category_appearance">অবয়ব</string>
<string name="preference_category_general">সাধারণ</string> <string name="preference_category_general">সাধারণ</string>
@ -89,9 +98,11 @@
<string name="logging_in_message">অনুগ্রহ করে অপেক্ষা করুন…</string> <string name="logging_in_message">অনুগ্রহ করে অপেক্ষা করুন…</string>
<string name="updating_caption_title">ক্যাপশন ও বিবরণ হালনাগাদ করা হচ্ছে</string> <string name="updating_caption_title">ক্যাপশন ও বিবরণ হালনাগাদ করা হচ্ছে</string>
<string name="updating_caption_message">অনুগ্রহ করে অপেক্ষা করুন…</string> <string name="updating_caption_message">অনুগ্রহ করে অপেক্ষা করুন…</string>
<string name="login_success" fuzzy="true">প্রবেশ সফল!</string> <string name="login_success">প্রবেশ সফল</string>
<string name="login_failed">প্রবেশ ব্যর্থ!</string> <string name="login_failed">প্রবেশ ব্যর্থ!</string>
<string name="upload_failed">ফাইল পাওয়া যায়নি। আরেকটি ফাইল চেষ্টা করুন।</string> <string name="upload_failed">ফাইল পাওয়া যায়নি। আরেকটি ফাইল চেষ্টা করুন।</string>
<string name="retry_limit_reached">সর্বোচ্চ পুনচেষ্টা করার সীমা পেরিয়ে গেছে! অনুগ্রহ করে আপলোডটি বাতিল করে আবার চেষ্টা করুন।</string>
<string name="unrestricted_battery_mode">ব্যাটারি অপ্টিমাইজেশন বন্ধ করবেন?</string>
<string name="authentication_failed">প্রমাণীকরণ ব্যর্থ হয়েছে। অনুগ্রহ করে আবার প্রবেশ করুন।</string> <string name="authentication_failed">প্রমাণীকরণ ব্যর্থ হয়েছে। অনুগ্রহ করে আবার প্রবেশ করুন।</string>
<string name="uploading_started">আপলোড আরম্ভ হয়েছে!</string> <string name="uploading_started">আপলোড আরম্ভ হয়েছে!</string>
<string name="uploading_queued">আপলোড সারিবদ্ধ করা হয়েছে (সীমিত সংযোগ মোড সক্রিয় করা)</string> <string name="uploading_queued">আপলোড সারিবদ্ধ করা হয়েছে (সীমিত সংযোগ মোড সক্রিয় করা)</string>
@ -113,6 +124,8 @@
<string name="menu_from_camera">ছবি তুলুন</string> <string name="menu_from_camera">ছবি তুলুন</string>
<string name="menu_nearby">কাছাকাছি</string> <string name="menu_nearby">কাছাকাছি</string>
<string name="provider_contributions">আমার আপলোড</string> <string name="provider_contributions">আমার আপলোড</string>
<string name="menu_copy_link">লিংক কপি করুন</string>
<string name="menu_link_copied">লিঙ্কটি ক্লিপবোর্ডে কপি করা হয়েছে।</string>
<string name="menu_share">বণ্টন</string> <string name="menu_share">বণ্টন</string>
<string name="menu_view_file_page">ফাইলের পাতাটি দেখুন</string> <string name="menu_view_file_page">ফাইলের পাতাটি দেখুন</string>
<string name="share_title_hint">ক্যাপশন (আবশ্যক)</string> <string name="share_title_hint">ক্যাপশন (আবশ্যক)</string>
@ -123,7 +136,8 @@
<string name="login_failed_throttled">খুব বেশি অসফল প্রচেষ্টা। অনুগ্রহ করে কয়েক মিনিট পরে আবারও চেষ্টা করুন।</string> <string name="login_failed_throttled">খুব বেশি অসফল প্রচেষ্টা। অনুগ্রহ করে কয়েক মিনিট পরে আবারও চেষ্টা করুন।</string>
<string name="login_failed_blocked">দুঃখিত, এই ব্যবহারকারীকে কমন্সে বাধা দেয়া হয়েছে</string> <string name="login_failed_blocked">দুঃখিত, এই ব্যবহারকারীকে কমন্সে বাধা দেয়া হয়েছে</string>
<string name="login_failed_2fa_needed">আপনাকে অবশ্যই আপনার দু\'স্তরের সত্যায়নকরণ কোড দিতে হবে।</string> <string name="login_failed_2fa_needed">আপনাকে অবশ্যই আপনার দু\'স্তরের সত্যায়নকরণ কোড দিতে হবে।</string>
<string name="login_failed_generic" fuzzy="true">প্রবেশ ব্যর্থ</string> <string name="login_failed_email_auth_needed">আপনার ইমেল ঠিকানায় একটি লগইন যাচাইকরণ কোড পাঠানো হয়েছে। লগ ইন করার জন্য অনুগ্রহ করে কোডটি প্রদান করুন।</string>
<string name="login_failed_generic">প্রবেশ ব্যর্থ</string>
<string name="share_upload_button">আপলোড</string> <string name="share_upload_button">আপলোড</string>
<string name="multiple_share_base_title">এই সেটের নাম</string> <string name="multiple_share_base_title">এই সেটের নাম</string>
<string name="provider_modifications">পরিবর্তনসমূহ</string> <string name="provider_modifications">পরিবর্তনসমূহ</string>
@ -131,6 +145,7 @@
<string name="categories_search_text_hint">বিষয়শ্রেণী অনুসন্ধান</string> <string name="categories_search_text_hint">বিষয়শ্রেণী অনুসন্ধান</string>
<string name="depicts_search_text_hint">আপনার মিডিয়া চিত্রিত আইটেমগুলি অনুসন্ধান করুন (পর্বত, তাজমহল, ইত্যাদি)</string> <string name="depicts_search_text_hint">আপনার মিডিয়া চিত্রিত আইটেমগুলি অনুসন্ধান করুন (পর্বত, তাজমহল, ইত্যাদি)</string>
<string name="menu_save_categories">সংরক্ষণ</string> <string name="menu_save_categories">সংরক্ষণ</string>
<string name="menu_overflow_desc">ওভারফ্লো মেনু</string>
<string name="refresh_button">পুনঃসতেজ</string> <string name="refresh_button">পুনঃসতেজ</string>
<string name="display_list_button">তালিকা</string> <string name="display_list_button">তালিকা</string>
<string name="contributions_subtitle_zero">(আপলোড করেন নি)</string> <string name="contributions_subtitle_zero">(আপলোড করেন নি)</string>
@ -223,6 +238,7 @@
<string name="become_a_tester_title">বিটা টেস্টার হোন</string> <string name="become_a_tester_title">বিটা টেস্টার হোন</string>
<string name="become_a_tester_description">গুগল প্লেতে আমাদের বেটা চ্যানেলে যুক্ত হন! এতে নতুন বৈশিষ্ট্যের পাশাপাশি পুরানো বাগগুলো\'র সংশোধিত রুপ সবার আগে ব্যবহারের সুযোগ পাবেন</string> <string name="become_a_tester_description">গুগল প্লেতে আমাদের বেটা চ্যানেলে যুক্ত হন! এতে নতুন বৈশিষ্ট্যের পাশাপাশি পুরানো বাগগুলো\'র সংশোধিত রুপ সবার আগে ব্যবহারের সুযোগ পাবেন</string>
<string name="_2fa_code">2FA কোড</string> <string name="_2fa_code">2FA কোড</string>
<string name="email_auth_code">ইমেল যাচাইকরণ কোড</string>
<string name="logout_verification">আপনি কি সত্যিই প্রস্থান করতে চান?</string> <string name="logout_verification">আপনি কি সত্যিই প্রস্থান করতে চান?</string>
<string name="mediaimage_failed">মিডিয়া চিত্র ব্যর্থ হয়েছে</string> <string name="mediaimage_failed">মিডিয়া চিত্র ব্যর্থ হয়েছে</string>
<string name="no_subcategory_found">কোন উপবিষয়শ্রেনী পাওয়া যায় নি।</string> <string name="no_subcategory_found">কোন উপবিষয়শ্রেনী পাওয়া যায় নি।</string>
@ -243,6 +259,7 @@
<string name="navigation_item_about">সম্পর্কে</string> <string name="navigation_item_about">সম্পর্কে</string>
<string name="navigation_item_settings">সেটিং</string> <string name="navigation_item_settings">সেটিং</string>
<string name="navigation_item_feedback">প্রতিক্রিয়া</string> <string name="navigation_item_feedback">প্রতিক্রিয়া</string>
<string name="navigation_item_feedback_github">GitHub এর মাধ্যমে প্রতিক্রিয়া</string>
<string name="navigation_item_logout">প্রস্থান</string> <string name="navigation_item_logout">প্রস্থান</string>
<string name="navigation_item_info">ভূমিকা</string> <string name="navigation_item_info">ভূমিকা</string>
<string name="navigation_item_notification">বিজ্ঞপ্তি</string> <string name="navigation_item_notification">বিজ্ঞপ্তি</string>
@ -252,6 +269,7 @@
<string name="nearby_info_menu_wikidata_article">উইকিউপাত্ত আইটেম</string> <string name="nearby_info_menu_wikidata_article">উইকিউপাত্ত আইটেম</string>
<string name="nearby_info_menu_wikipedia_article">উইকিপিডিয়া নিবন্ধ</string> <string name="nearby_info_menu_wikipedia_article">উইকিপিডিয়া নিবন্ধ</string>
<string name="description_info">যতটা সম্ভব মিডিয়াটি বর্ণনা করুন: এটি কোথায় ধারণ করা হয়েছিল? এটি কি প্রদর্শন করে? এটির প্রসঙ্গ কি? ধারণকৃত বস্তু অথবা ব্যক্তির বর্ণনা করুন। সহজে অনুমান করা যায়না সেরকম তথ্য উদঘাটন করুন, উদাহরণস্বরূপ, যদি ল্যান্ডস্কেপ হয় তাহলে দিবসকালের সময় দিন।</string> <string name="description_info">যতটা সম্ভব মিডিয়াটি বর্ণনা করুন: এটি কোথায় ধারণ করা হয়েছিল? এটি কি প্রদর্শন করে? এটির প্রসঙ্গ কি? ধারণকৃত বস্তু অথবা ব্যক্তির বর্ণনা করুন। সহজে অনুমান করা যায়না সেরকম তথ্য উদঘাটন করুন, উদাহরণস্বরূপ, যদি ল্যান্ডস্কেপ হয় তাহলে দিবসকালের সময় দিন।</string>
<string name="caption_info">দয়া করে ছবির একটি সংক্ষিপ্ত বিবরণ লিখুন। প্রথম ক্যাপশনটি ছবির শিরোনাম হিসেবে ব্যবহার করা হবে। ২৫৫ অক্ষরের মধ্যে সীমাবদ্ধ।</string>
<string name="upload_problem_exist">এই চিত্রের সম্ভাব্য সমস্যাগুলি:</string> <string name="upload_problem_exist">এই চিত্রের সম্ভাব্য সমস্যাগুলি:</string>
<string name="upload_problem_image_dark">চিত্রটি খুব অন্ধকারযুক্ত।</string> <string name="upload_problem_image_dark">চিত্রটি খুব অন্ধকারযুক্ত।</string>
<string name="upload_problem_image_blurry">চিত্রটি অস্পষ্ট।</string> <string name="upload_problem_image_blurry">চিত্রটি অস্পষ্ট।</string>
@ -275,12 +293,13 @@
<string name="nominated_see_more">বিশদের জন্য ওয়েবপৃষ্ঠা দেখুন</string> <string name="nominated_see_more">বিশদের জন্য ওয়েবপৃষ্ঠা দেখুন</string>
<string name="skip_login">এড়ান</string> <string name="skip_login">এড়ান</string>
<string name="navigation_item_login">প্রবেশ করুন</string> <string name="navigation_item_login">প্রবেশ করুন</string>
<string name="skip_login_title" fuzzy="true">আপনি কি সত্যিই প্রবেশকরণ এড়িয়ে যেতে চান?</string> <string name="skip_login_title">আপনি কি সত্যিই লগ-ইন এড়িয়ে যেতে চান?</string>
<string name="skip_login_message" fuzzy="true">ভবিষ্যতে চিত্র আপলোড করতে চাইলে আপনাকে প্রবেশ করতে হবে।</string> <string name="skip_login_message">ভবিষ্যতে চিত্র আপলোড করতে চাইলে আপনাকে প্রবেশ করতে হবে।</string>
<string name="login_alert_message">এই সুবিধাটি ব্যাবহার করতে প্রবেশ করুন</string> <string name="login_alert_message">এই সুবিধাটি ব্যাবহার করতে প্রবেশ করুন</string>
<string name="copy_wikicode">উইকিপাঠ্যটি ক্লিপবোর্ডে অনুলিপি করুন</string> <string name="copy_wikicode">উইকিপাঠ্যটি ক্লিপবোর্ডে অনুলিপি করুন</string>
<string name="wikicode_copied">উইকিপাঠ্যটি ক্লিপবোর্ডে অনুলিপি করা হয়েছে</string> <string name="wikicode_copied">উইকিপাঠ্যটি ক্লিপবোর্ডে অনুলিপি করা হয়েছে</string>
<string name="nearby_location_not_available">কাছাকাছি সঠিকভাবে কাজ করছে না, অবস্থান উপলব্ধ নয়।</string> <string name="nearby_location_not_available">কাছাকাছি সঠিকভাবে কাজ করছে না, অবস্থান উপলব্ধ নয়।</string>
<string name="nearby_showing_pins_offline">ইন্টারনেট অনুপলব্ধ। শুধুমাত্র ক্যাশে করা স্থানগুলো দেখানো হচ্ছে।</string>
<string name="location_permission_rationale_nearby">কাছাকাছি স্থানসমূহের একটি তালিকা প্রদর্শন করতে অনুমতি প্রয়োজন</string> <string name="location_permission_rationale_nearby">কাছাকাছি স্থানসমূহের একটি তালিকা প্রদর্শন করতে অনুমতি প্রয়োজন</string>
<string name="nearby_directions">দিকনির্দেশ</string> <string name="nearby_directions">দিকনির্দেশ</string>
<string name="nearby_wikidata">উইকিউপাত্ত</string> <string name="nearby_wikidata">উইকিউপাত্ত</string>
@ -334,19 +353,26 @@
<string name="quiz_screenshot_question">এই স্ক্রিনশটটি কি আপলোড করা ঠিক হয়েছে?</string> <string name="quiz_screenshot_question">এই স্ক্রিনশটটি কি আপলোড করা ঠিক হয়েছে?</string>
<string name="share_app_title">অ্যাপ শেয়ার করুন</string> <string name="share_app_title">অ্যাপ শেয়ার করুন</string>
<string name="rotate">ঘোরান</string> <string name="rotate">ঘোরান</string>
<string name="error_fetching_nearby_places" fuzzy="true">কাছাকাছি স্থানগুলি আনতে ত্রুটি।</string> <string name="error_fetching_nearby_places">কাছাকাছি জায়গাগুলি লোড করা যায়নি</string>
<string name="no_pictures_in_this_area">এই এলাকার কোনও ছবি নেই</string>
<string name="no_nearby_places_around">আশেপাশে কোনো এলাকা পাওয়া যায়নি</string> <string name="no_nearby_places_around">আশেপাশে কোনো এলাকা পাওয়া যায়নি</string>
<string name="error_fetching_nearby_monuments">আশেপাশের স্মৃতিস্তম্ভগুলি আনায়নে ত্রুটি৷</string> <string name="error_fetching_nearby_monuments">আশেপাশের স্মৃতিস্তম্ভগুলি আনায়নে ত্রুটি৷</string>
<string name="no_recent_searches">কোনও সাম্প্রতিক অনুসন্ধান নেই</string> <string name="no_recent_searches">কোনও সাম্প্রতিক অনুসন্ধান নেই</string>
<string name="delete_recent_searches_dialog">আপনি কি নিশ্চিত যে আপনি আপনার অনুসন্ধান ইতিহাস মুছে ফেলতে চান?</string> <string name="delete_recent_searches_dialog">আপনি কি নিশ্চিত যে আপনি আপনার অনুসন্ধান ইতিহাস মুছে ফেলতে চান?</string>
<string name="cancel_upload_dialog">আপনি কি নিশ্চিত যে আপনি এই আপলোডটি বাতিল করতে চান?</string>
<string name="delete_search_dialog">আপনি কি এই অনুসন্ধানটি মুছে ফেলতে চান?</string>
<string name="search_history_deleted">অনুসন্ধানের ইতিহাস মুছে ফেলা হয়েছে</string>
<string name="nominate_delete">অপসারণের জন্য মনোনীত করুন</string> <string name="nominate_delete">অপসারণের জন্য মনোনীত করুন</string>
<string name="delete">অপসারণ</string> <string name="delete">অপসারণ</string>
<string name="Achievements">কৃতিত্বগুলি</string> <string name="Achievements">কৃতিত্বগুলি</string>
<string name="Profile">প্রোফাইল</string> <string name="Profile">প্রোফাইল</string>
<string name="badges">ব্যাজ</string>
<string name="statistics">পরিসংখ্যান</string> <string name="statistics">পরিসংখ্যান</string>
<string name="statistics_thanks">ধন্যবাদ পেয়েছেন</string> <string name="statistics_thanks">ধন্যবাদ পেয়েছেন</string>
<string name="statistics_featured">নির্বাচিত ছবি</string> <string name="statistics_featured">নির্বাচিত ছবি</string>
<string name="level" fuzzy="true">স্তর</string> <string name="statistics_wikidata_edits">\"কাছাকাছি স্থান\" এর মাধ্যমে ছবি</string>
<string name="level">স্তর %d</string>
<string name="profileLevel">%s (স্তর %s )</string>
<string name="images_uploaded">আপলোডকৃত চিত্র</string> <string name="images_uploaded">আপলোডকৃত চিত্র</string>
<string name="image_reverts">ছবিগুলো প্রত্যাবর্তন করা হয়নি</string> <string name="image_reverts">ছবিগুলো প্রত্যাবর্তন করা হয়নি</string>
<string name="images_used_by_wiki">ব্যবহৃত ছবি</string> <string name="images_used_by_wiki">ব্যবহৃত ছবি</string>
@ -539,4 +565,5 @@
<string name="failed">ব্যর্থ হয়েছে</string> <string name="failed">ব্যর্থ হয়েছে</string>
<string name="caption">ক্যাপশন</string> <string name="caption">ক্যাপশন</string>
<string name="caption_copied_to_clipboard">ক্যাপশন ক্লিপবোর্ডে অনুলিপি করা হয়েছে</string> <string name="caption_copied_to_clipboard">ক্যাপশন ক্লিপবোর্ডে অনুলিপি করা হয়েছে</string>
<string name="nominated_for_deletion_btn">অপসারণের জন্য মনোনীত</string>
</resources> </resources>

View file

@ -448,7 +448,7 @@
<string name="deletion_reason_bad_for_my_privacy">Uvědomil/a jsem si, že je to špatné pro mé soukromí</string> <string name="deletion_reason_bad_for_my_privacy">Uvědomil/a jsem si, že je to špatné pro mé soukromí</string>
<string name="deletion_reason_no_longer_want_public">Změnil/a jsem názor, nechci, aby to bylo veřejně viditelné</string> <string name="deletion_reason_no_longer_want_public">Změnil/a jsem názor, nechci, aby to bylo veřejně viditelné</string>
<string name="deletion_reason_not_interesting">Omlouváme se, že tento obrázek není zajímavý pro encyklopedii</string> <string name="deletion_reason_not_interesting">Omlouváme se, že tento obrázek není zajímavý pro encyklopedii</string>
<string name="uploaded_by_myself">Náhráno mnou %1$s, použito v(e) %2$d článku/článcích.</string> <string name="uploaded_by_myself" fuzzy="true">Náhráno mnou %1$s, použito v(e) %2$d článku/článcích.</string>
<string name="no_uploads">Vítejte na Commons!\n\nNahrajte svá první média klepnutím na tlačítko přidat.</string> <string name="no_uploads">Vítejte na Commons!\n\nNahrajte svá první média klepnutím na tlačítko přidat.</string>
<string name="no_categories_selected">Nebyly vybrány žádné kategorie</string> <string name="no_categories_selected">Nebyly vybrány žádné kategorie</string>
<string name="no_categories_selected_warning_desc">Obrázky bez kategorií jsou používány jen zřídka. Opravdu chcete nahrát obrázek bez výběru kategorií?</string> <string name="no_categories_selected_warning_desc">Obrázky bez kategorií jsou používány jen zřídka. Opravdu chcete nahrát obrázek bez výběru kategorií?</string>

View file

@ -135,7 +135,7 @@
<string name="categories_not_found">Ingen kategorier matchende %1$s er fundet</string> <string name="categories_not_found">Ingen kategorier matchende %1$s er fundet</string>
<string name="depictions_not_found">Der blev ikke fundet nogen Wikidata-elementer, der matcher %1$s</string> <string name="depictions_not_found">Der blev ikke fundet nogen Wikidata-elementer, der matcher %1$s</string>
<string name="no_child_classes">%1$s har ingen underklasser</string> <string name="no_child_classes">%1$s har ingen underklasser</string>
<string name="no_parent_classes">%1$s har ingen forældreklasser</string> <string name="no_parent_classes">%1$s har ingen overordnede klasser</string>
<string name="categories_skip_explanation">Tilføj kategorier for at gøre dine billeder mere synlig på Wikimedia Commons. Begynd at taste for at tilføje kategorier.</string> <string name="categories_skip_explanation">Tilføj kategorier for at gøre dine billeder mere synlig på Wikimedia Commons. Begynd at taste for at tilføje kategorier.</string>
<string name="categories_activity_title">Kategorier</string> <string name="categories_activity_title">Kategorier</string>
<string name="title_activity_settings">Indstillinger</string> <string name="title_activity_settings">Indstillinger</string>
@ -419,7 +419,7 @@
<string name="deletion_reason_bad_for_my_privacy">Jeg indså, det var skidt for mit privatliv</string> <string name="deletion_reason_bad_for_my_privacy">Jeg indså, det var skidt for mit privatliv</string>
<string name="deletion_reason_no_longer_want_public">Jeg ombestemte mig, jeg ønsker ikke at det skal være offentligt synligt længere</string> <string name="deletion_reason_no_longer_want_public">Jeg ombestemte mig, jeg ønsker ikke at det skal være offentligt synligt længere</string>
<string name="deletion_reason_not_interesting">Beklager dette billede er ikke interessant for en encyklopædi</string> <string name="deletion_reason_not_interesting">Beklager dette billede er ikke interessant for en encyklopædi</string>
<string name="uploaded_by_myself">Uploadet af mig selv på %1$s , brugt i %2$d artikel(er).</string> <string name="uploaded_by_myself">Uploadet af mig selv på %1$s , brugt i mindst %2$d artikel(er).</string>
<string name="no_uploads">Velkommen til Commons!\n\nUpload dit første medie ved at trykke på Tilføj-knappen.</string> <string name="no_uploads">Velkommen til Commons!\n\nUpload dit første medie ved at trykke på Tilføj-knappen.</string>
<string name="no_categories_selected">Ingen kategorier valgt</string> <string name="no_categories_selected">Ingen kategorier valgt</string>
<string name="no_categories_selected_warning_desc">Billeder uden kategorier er sjældent brugbare. Er du sikker på, at du vil fortsætte uden at vælge kategorier?</string> <string name="no_categories_selected_warning_desc">Billeder uden kategorier er sjældent brugbare. Er du sikker på, at du vil fortsætte uden at vælge kategorier?</string>
@ -584,6 +584,8 @@
<string name="title_for_media">MEDIER</string> <string name="title_for_media">MEDIER</string>
<string name="title_for_child_classes">UNDERKLASSER</string> <string name="title_for_child_classes">UNDERKLASSER</string>
<string name="title_for_parent_classes">OVERORDNEDE KLASSER</string> <string name="title_for_parent_classes">OVERORDNEDE KLASSER</string>
<string name="title_for_subcategories">UNDERKATEGORIER</string>
<string name="title_for_parent_categories">OVERORDNEDE KATEGORIER</string>
<string name="upload_nearby_place_found_title">Sted fundet i nærheden</string> <string name="upload_nearby_place_found_title">Sted fundet i nærheden</string>
<string name="upload_nearby_place_found_description_plural">Er disse billeder af %1$s ?</string> <string name="upload_nearby_place_found_description_plural">Er disse billeder af %1$s ?</string>
<string name="upload_nearby_place_found_description_singular">Er dette et billede af %1$s?</string> <string name="upload_nearby_place_found_description_singular">Er dette et billede af %1$s?</string>
@ -828,4 +830,5 @@
<string name="show_in_nearby">Vis i I nærheden</string> <string name="show_in_nearby">Vis i I nærheden</string>
<string name="image_tag_line_created_and_uploaded_by">Oprettet og uploadet af: %1$s</string> <string name="image_tag_line_created_and_uploaded_by">Oprettet og uploadet af: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">Oprettet af %1$s og uploadet af %2$s</string> <string name="image_tag_line_created_by_and_uploaded_by">Oprettet af %1$s og uploadet af %2$s</string>
<string name="nominated_for_deletion_btn">Nomineret til sletning</string>
</resources> </resources>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Authors: <!-- Authors:
* *surak*
* BPX-web * BPX-web
* Bjarncraft * Bjarncraft
* Brettchenweber * Brettchenweber
@ -453,7 +454,7 @@
<string name="deletion_reason_bad_for_my_privacy">Ich habe erkannt, dass es schlecht für meine Privatsphäre ist.</string> <string name="deletion_reason_bad_for_my_privacy">Ich habe erkannt, dass es schlecht für meine Privatsphäre ist.</string>
<string name="deletion_reason_no_longer_want_public">Ich habe meine Meinung geändert. Ich möchte nicht mehr, dass es öffentlich sichtbar ist.</string> <string name="deletion_reason_no_longer_want_public">Ich habe meine Meinung geändert. Ich möchte nicht mehr, dass es öffentlich sichtbar ist.</string>
<string name="deletion_reason_not_interesting">Entschuldigung, aber dieses Bild ist für eine Enzyklopädie nicht relevant.</string> <string name="deletion_reason_not_interesting">Entschuldigung, aber dieses Bild ist für eine Enzyklopädie nicht relevant.</string>
<string name="uploaded_by_myself">Von mir selbst hochgeladen am %1$s, verwendet in %2$d Artikel(n).</string> <string name="uploaded_by_myself">Von mir selbst hochgeladen am %1$s, verwendet in mindestens %2$d Artikel(n).</string>
<string name="no_uploads">Willkommen bei Commons!\n\nLade deine erste Datei hoch, indem du auf die Hinzufügen-Schaltfläche tippst.</string> <string name="no_uploads">Willkommen bei Commons!\n\nLade deine erste Datei hoch, indem du auf die Hinzufügen-Schaltfläche tippst.</string>
<string name="no_categories_selected">Keine Kategorien ausgewählt</string> <string name="no_categories_selected">Keine Kategorien ausgewählt</string>
<string name="no_categories_selected_warning_desc">Bilder ohne Kategorien sind selten nutzbar. Bist du sicher, dass du ohne die Auswahl von Kategorien hochladen möchtest?</string> <string name="no_categories_selected_warning_desc">Bilder ohne Kategorien sind selten nutzbar. Bist du sicher, dass du ohne die Auswahl von Kategorien hochladen möchtest?</string>
@ -615,6 +616,8 @@
<string name="title_for_media">MEDIA</string> <string name="title_for_media">MEDIA</string>
<string name="title_for_child_classes">CHILD CLASSES</string> <string name="title_for_child_classes">CHILD CLASSES</string>
<string name="title_for_parent_classes">PARENT CLASSES</string> <string name="title_for_parent_classes">PARENT CLASSES</string>
<string name="title_for_subcategories">UNTERKATEGORIEN</string>
<string name="title_for_parent_categories">ÜBERGEORDNETE KATEGORIEN</string>
<string name="upload_nearby_place_found_title">Ort in der Nähe gefunden</string> <string name="upload_nearby_place_found_title">Ort in der Nähe gefunden</string>
<string name="upload_nearby_place_found_description_plural">Sind das Bilder von %1$s ?</string> <string name="upload_nearby_place_found_description_plural">Sind das Bilder von %1$s ?</string>
<string name="upload_nearby_place_found_description_singular">Ist das ein Foto von %1$s?</string> <string name="upload_nearby_place_found_description_singular">Ist das ein Foto von %1$s?</string>

View file

@ -256,7 +256,7 @@
<string name="navigation_drawer_close">Κλείσιμο</string> <string name="navigation_drawer_close">Κλείσιμο</string>
<string name="navigation_item_home">Αρχική σελίδα</string> <string name="navigation_item_home">Αρχική σελίδα</string>
<string name="navigation_item_upload">Μεταφόρτωση αρχείου</string> <string name="navigation_item_upload">Μεταφόρτωση αρχείου</string>
<string name="navigation_item_nearby">Κοντά σας</string> <string name="navigation_item_nearby">Κοντινά</string>
<string name="navigation_item_about">Σχετικά</string> <string name="navigation_item_about">Σχετικά</string>
<string name="navigation_item_settings">Ρυθμίσεις</string> <string name="navigation_item_settings">Ρυθμίσεις</string>
<string name="navigation_item_feedback">Ανατροφοδότηση</string> <string name="navigation_item_feedback">Ανατροφοδότηση</string>
@ -433,7 +433,7 @@
<string name="deletion_reason_bad_for_my_privacy">Συνειδητοποίησα ότι είναι κακό για την ιδιωτικότητά μου</string> <string name="deletion_reason_bad_for_my_privacy">Συνειδητοποίησα ότι είναι κακό για την ιδιωτικότητά μου</string>
<string name="deletion_reason_no_longer_want_public">Άλλαξα γνώμη, δε θέλω να προβάλλεται πλέον δημόσια</string> <string name="deletion_reason_no_longer_want_public">Άλλαξα γνώμη, δε θέλω να προβάλλεται πλέον δημόσια</string>
<string name="deletion_reason_not_interesting">Συγγνώμη, αυτή η φωτογραφία δεν είναι ενδιαφέρουσα για μια εγκυκλοπαίδεια</string> <string name="deletion_reason_not_interesting">Συγγνώμη, αυτή η φωτογραφία δεν είναι ενδιαφέρουσα για μια εγκυκλοπαίδεια</string>
<string name="uploaded_by_myself">Ανέβηκε από εμένα στο %1$s, χρησιμοποιήθηκε σε %2$d άρθρο/α</string> <string name="uploaded_by_myself" fuzzy="true">Ανέβηκε από εμένα στο %1$s, χρησιμοποιήθηκε σε %2$d άρθρο/α</string>
<string name="no_uploads">Καλώς ήρθατε στα Commons!\n\nΑνεβάστε τα πρώτα σας πολυμέσα πατώντας το κουμπί της προσθήκης.</string> <string name="no_uploads">Καλώς ήρθατε στα Commons!\n\nΑνεβάστε τα πρώτα σας πολυμέσα πατώντας το κουμπί της προσθήκης.</string>
<string name="no_categories_selected">Δεν επιλέχθηκαν κατηγορίες</string> <string name="no_categories_selected">Δεν επιλέχθηκαν κατηγορίες</string>
<string name="no_categories_selected_warning_desc">Οι εικόνες χωρίς κατηγορίες χρησιμοποιούνται σπάνια. Θέλετε πράγματι να συνεχίσετε δίχως να επιλέξετε κατηγορίες;</string> <string name="no_categories_selected_warning_desc">Οι εικόνες χωρίς κατηγορίες χρησιμοποιούνται σπάνια. Θέλετε πράγματι να συνεχίσετε δίχως να επιλέξετε κατηγορίες;</string>
@ -803,6 +803,7 @@
<string name="talk">Συζήτηση</string> <string name="talk">Συζήτηση</string>
<string name="write_something_about_the_item">Γράψτε κάτι για το αντικείμενο \'%1$s\'. Θα είναι δημόσια ορατό.</string> <string name="write_something_about_the_item">Γράψτε κάτι για το αντικείμενο \'%1$s\'. Θα είναι δημόσια ορατό.</string>
<string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">Το \'%1$s\' δεν υφίσταται πλέον, καμία φωτογραφία δεν μπορεί να εξαχθεί.</string> <string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">Το \'%1$s\' δεν υφίσταται πλέον, καμία φωτογραφία δεν μπορεί να εξαχθεί.</string>
<string name="is_at_a_different_place_wikidata">Το \'%1$s\' βρίσκεται σε διαφορετικό μέρος.</string>
<string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">Το \'%1$s\' βρίσκεται σε διαφορετική θέση. Παρακαλούμε προσδιορίστε τη σωστή θέση παρακαλώ, και αν είναι εφικτό, γράψτε το σωστό γεωγραφικό πλάτος και μήκος.</string> <string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">Το \'%1$s\' βρίσκεται σε διαφορετική θέση. Παρακαλούμε προσδιορίστε τη σωστή θέση παρακαλώ, και αν είναι εφικτό, γράψτε το σωστό γεωγραφικό πλάτος και μήκος.</string>
<string name="other_problem_or_information_please_explain_below">Άλλο πρόβλημα ή πληροφορίες (παρακαλούμε εξηγήστε παρακάτω).</string> <string name="other_problem_or_information_please_explain_below">Άλλο πρόβλημα ή πληροφορίες (παρακαλούμε εξηγήστε παρακάτω).</string>
<string name="feedback_destination_note">Τα σχόλιά σας δημοσιεύονται στην ακόλουθη σελίδα wiki: &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\"&gt;Commons:Εφαρμογή για κινητά/Σχόλια&lt;/a&gt;</string> <string name="feedback_destination_note">Τα σχόλιά σας δημοσιεύονται στην ακόλουθη σελίδα wiki: &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\"&gt;Commons:Εφαρμογή για κινητά/Σχόλια&lt;/a&gt;</string>
@ -828,4 +829,9 @@
<string name="account">Λογαριασμός</string> <string name="account">Λογαριασμός</string>
<string name="caption">Λεζάντα</string> <string name="caption">Λεζάντα</string>
<string name="caption_copied_to_clipboard">Η λεζάντα αντιγράφηκε στο πρόχειρο</string> <string name="caption_copied_to_clipboard">Η λεζάντα αντιγράφηκε στο πρόχειρο</string>
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Συγχαρητήρια, όλες οι φωτογραφίες σε αυτό το άλμπουμ έχουν είτε μεταφορτωθεί είτε επισημανθεί για μη μεταφόρτωση.</string>
<string name="show_in_explore">Εμφάνιση στην Εξερεύνηση</string>
<string name="show_in_nearby">Εμφάνιση στα Κοντινά</string>
<string name="image_tag_line_created_and_uploaded_by">Δημιουργήθηκε και μεταφορτώθηκε από: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">Δημιουργήθηκε από %1$s και μεταφορτώθηκε από %2$s</string>
</resources> </resources>

View file

@ -408,7 +408,7 @@
<string name="deletion_reason_bad_for_my_privacy">Mi eksciis ke ĝi esta malbona por mia privateco</string> <string name="deletion_reason_bad_for_my_privacy">Mi eksciis ke ĝi esta malbona por mia privateco</string>
<string name="deletion_reason_no_longer_want_public">Mi ŝanĝis mian preferon; mi ne plu volas ke ĝi estu publike videbla</string> <string name="deletion_reason_no_longer_want_public">Mi ŝanĝis mian preferon; mi ne plu volas ke ĝi estu publike videbla</string>
<string name="deletion_reason_not_interesting">Domaĝe, ĉi tiu bildo ne estas interesa por enciklopedio</string> <string name="deletion_reason_not_interesting">Domaĝe, ĉi tiu bildo ne estas interesa por enciklopedio</string>
<string name="uploaded_by_myself">Alŝutita de mi je %1$s, uzata en %2$d artikolo(j).</string> <string name="uploaded_by_myself" fuzzy="true">Alŝutita de mi je %1$s, uzata en %2$d artikolo(j).</string>
<string name="no_uploads">Bonvenon al Komunejo!\n\nAlŝutu vian unuan aŭdvidaĵon per frapeto de la butono \'Aldoni\'.</string> <string name="no_uploads">Bonvenon al Komunejo!\n\nAlŝutu vian unuan aŭdvidaĵon per frapeto de la butono \'Aldoni\'.</string>
<string name="no_categories_selected">Neniu Elektita Kategorio</string> <string name="no_categories_selected">Neniu Elektita Kategorio</string>
<string name="no_categories_selected_warning_desc">Bildoj sen kategorioj estas malofte uzebla. Ĉu vi certas, ke vi volas daŭrigi sen elekti kategoriojn?</string> <string name="no_categories_selected_warning_desc">Bildoj sen kategorioj estas malofte uzebla. Ĉu vi certas, ke vi volas daŭrigi sen elekti kategoriojn?</string>

View file

@ -30,6 +30,7 @@
* Jduranboger * Jduranboger
* Jelou * Jelou
* Johnny243 * Johnny243
* JorgeElias2302
* Josuert * Josuert
* Juanman * Juanman
* Keneth Urrutia * Keneth Urrutia
@ -152,6 +153,7 @@
<string name="menu_nearby">Cercanos</string> <string name="menu_nearby">Cercanos</string>
<string name="provider_contributions">Mis subidas</string> <string name="provider_contributions">Mis subidas</string>
<string name="menu_copy_link">Copiar enlace</string> <string name="menu_copy_link">Copiar enlace</string>
<string name="menu_link_copied">El enlace ha sido copiado al portapapeles.</string>
<string name="menu_share">Compartir</string> <string name="menu_share">Compartir</string>
<string name="menu_view_file_page">Ver página del archivo</string> <string name="menu_view_file_page">Ver página del archivo</string>
<string name="share_title_hint">Leyenda (requerido)</string> <string name="share_title_hint">Leyenda (requerido)</string>
@ -162,6 +164,7 @@
<string name="login_failed_throttled">Demasiados intentos fallidos. Inténtalo de nuevo en unos minutos.</string> <string name="login_failed_throttled">Demasiados intentos fallidos. Inténtalo de nuevo en unos minutos.</string>
<string name="login_failed_blocked">Lo sentimos, este usuario ha sido bloqueado en Commons</string> <string name="login_failed_blocked">Lo sentimos, este usuario ha sido bloqueado en Commons</string>
<string name="login_failed_2fa_needed">Debe proporcionar su código de autenticación de dos factores.</string> <string name="login_failed_2fa_needed">Debe proporcionar su código de autenticación de dos factores.</string>
<string name="login_failed_email_auth_needed">Se ha enviado un código de verificación de inicio de sesión a tu correo electrónico. Indícalo para iniciar sesión.</string>
<string name="login_failed_generic">Falló el inicio de sesión</string> <string name="login_failed_generic">Falló el inicio de sesión</string>
<string name="share_upload_button">Subir</string> <string name="share_upload_button">Subir</string>
<string name="multiple_share_base_title">Nombrar este conjunto</string> <string name="multiple_share_base_title">Nombrar este conjunto</string>
@ -267,6 +270,7 @@
<string name="become_a_tester_title">Prueba la versión beta</string> <string name="become_a_tester_title">Prueba la versión beta</string>
<string name="become_a_tester_description">Apúntate a nuestro canal beta en Google Play y obtén acceso a funcionalidades nuevas y correcciones de errores</string> <string name="become_a_tester_description">Apúntate a nuestro canal beta en Google Play y obtén acceso a funcionalidades nuevas y correcciones de errores</string>
<string name="_2fa_code">Código de autenticación de 2 pasos</string> <string name="_2fa_code">Código de autenticación de 2 pasos</string>
<string name="email_auth_code">Código de verificación de correo electrónico</string>
<string name="logout_verification">¿Confirmas que quieres salir?</string> <string name="logout_verification">¿Confirmas que quieres salir?</string>
<string name="mediaimage_failed">Falló la imagen de multimedia</string> <string name="mediaimage_failed">Falló la imagen de multimedia</string>
<string name="no_subcategory_found">No se encontró ninguna subcategoría</string> <string name="no_subcategory_found">No se encontró ninguna subcategoría</string>
@ -327,6 +331,7 @@
<string name="copy_wikicode">Copia el wikitexto al portapapeles</string> <string name="copy_wikicode">Copia el wikitexto al portapapeles</string>
<string name="wikicode_copied">El wikitexto fue copiado al portapapeles</string> <string name="wikicode_copied">El wikitexto fue copiado al portapapeles</string>
<string name="nearby_location_not_available">Cercanos no puede funcionar correctamente. La ubicación no está disponible.</string> <string name="nearby_location_not_available">Cercanos no puede funcionar correctamente. La ubicación no está disponible.</string>
<string name="nearby_showing_pins_offline">Internet no disponible. Solo se muestran ubicaciones en caché.</string>
<string name="upload_location_access_denied">Acceso a la ubicación denegado. Configura tu ubicación manualmente para utilizar esta función.</string> <string name="upload_location_access_denied">Acceso a la ubicación denegado. Configura tu ubicación manualmente para utilizar esta función.</string>
<string name="location_permission_rationale_nearby">Se necesita permiso para mostrar una lista de lugares cercanos</string> <string name="location_permission_rationale_nearby">Se necesita permiso para mostrar una lista de lugares cercanos</string>
<string name="location_permission_rationale_explore">Se necesita permiso para mostrar una lista de lugares cercanos</string> <string name="location_permission_rationale_explore">Se necesita permiso para mostrar una lista de lugares cercanos</string>
@ -416,6 +421,7 @@
<string name="statistics_featured">Imágenes destacadas</string> <string name="statistics_featured">Imágenes destacadas</string>
<string name="statistics_wikidata_edits">Imágenes vía \"Sitios Cercanos\"</string> <string name="statistics_wikidata_edits">Imágenes vía \"Sitios Cercanos\"</string>
<string name="level">Nivel %d</string> <string name="level">Nivel %d</string>
<string name="profileLevel">%s (Nivel %s)</string>
<string name="images_uploaded">Imágenes subidas</string> <string name="images_uploaded">Imágenes subidas</string>
<string name="image_reverts">Imágenes no revertidas</string> <string name="image_reverts">Imágenes no revertidas</string>
<string name="images_used_by_wiki">Imágenes utilizadas</string> <string name="images_used_by_wiki">Imágenes utilizadas</string>
@ -447,6 +453,7 @@
<string name="map_application_missing">No se encontró una aplicación de mapas compatible en tu dispositivo. Instala una para usar esta característica.</string> <string name="map_application_missing">No se encontró una aplicación de mapas compatible en tu dispositivo. Instala una para usar esta característica.</string>
<string name="title_page_bookmarks_pictures">Imágenes</string> <string name="title_page_bookmarks_pictures">Imágenes</string>
<string name="title_page_bookmarks_locations">Ubicaciones</string> <string name="title_page_bookmarks_locations">Ubicaciones</string>
<string name="title_page_bookmarks_categories">Categorías</string>
<string name="menu_bookmark">Añadir o quitar de marcadores</string> <string name="menu_bookmark">Añadir o quitar de marcadores</string>
<string name="provider_bookmarks">Marcadores</string> <string name="provider_bookmarks">Marcadores</string>
<string name="bookmark_empty">No has añadido ningún marcador</string> <string name="bookmark_empty">No has añadido ningún marcador</string>
@ -457,7 +464,7 @@
<string name="deletion_reason_bad_for_my_privacy">Me di cuenta que es malo para mi privacidad</string> <string name="deletion_reason_bad_for_my_privacy">Me di cuenta que es malo para mi privacidad</string>
<string name="deletion_reason_no_longer_want_public">Cambié de opinión, no quiero que siga siendo visible públicamente</string> <string name="deletion_reason_no_longer_want_public">Cambié de opinión, no quiero que siga siendo visible públicamente</string>
<string name="deletion_reason_not_interesting">Lo sentimos, esta imagen no es interesante para una enciclopedia</string> <string name="deletion_reason_not_interesting">Lo sentimos, esta imagen no es interesante para una enciclopedia</string>
<string name="uploaded_by_myself">Subida por mí mismo el %1$s, usado en %2$d artículo(s).</string> <string name="uploaded_by_myself" fuzzy="true">Subida por mí mismo el %1$s, usado en %2$d artículo(s).</string>
<string name="no_uploads">Te damos la bienvenida a Commons.\n\nCarga tu primer archivo mediante el botón Añadir.</string> <string name="no_uploads">Te damos la bienvenida a Commons.\n\nCarga tu primer archivo mediante el botón Añadir.</string>
<string name="no_categories_selected">No hay categorías seleccionadas</string> <string name="no_categories_selected">No hay categorías seleccionadas</string>
<string name="no_categories_selected_warning_desc">Las imágenes sin categorías raramente se pueden usar. ¿Seguro que quieres continuar sin seleccionar ninguna categoría?</string> <string name="no_categories_selected_warning_desc">Las imágenes sin categorías raramente se pueden usar. ¿Seguro que quieres continuar sin seleccionar ninguna categoría?</string>
@ -827,6 +834,7 @@
<string name="talk">Discusión</string> <string name="talk">Discusión</string>
<string name="write_something_about_the_item">Escriba algo sobre el elemento \'%1$s\'. Será visible públicamente.</string> <string name="write_something_about_the_item">Escriba algo sobre el elemento \'%1$s\'. Será visible públicamente.</string>
<string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">\' %1$s \' ya no existe, nunca se podrá tomar ninguna fotografía de él.</string> <string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">\' %1$s \' ya no existe, nunca se podrá tomar ninguna fotografía de él.</string>
<string name="is_at_a_different_place_wikidata">\'%1$s\' está en un lugar diferente.</string>
<string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">\' %1$s \' está en un lugar diferente. Especifique el lugar correcto a continuación y, si es posible, escriba la latitud y longitud correctas.</string> <string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">\' %1$s \' está en un lugar diferente. Especifique el lugar correcto a continuación y, si es posible, escriba la latitud y longitud correctas.</string>
<string name="other_problem_or_information_please_explain_below">Otro problema o información (por favor explique a continuación).</string> <string name="other_problem_or_information_please_explain_below">Otro problema o información (por favor explique a continuación).</string>
<string name="feedback_destination_note">Sus comentarios se publicarán en la siguiente página wiki: &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\"&gt;Commons:Mobile_app/Feedback&lt;/a&gt;</string> <string name="feedback_destination_note">Sus comentarios se publicarán en la siguiente página wiki: &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\"&gt;Commons:Mobile_app/Feedback&lt;/a&gt;</string>
@ -848,4 +856,21 @@
<string name="red_pin">Este lugar aún no tiene foto, ¡ve y toma una!</string> <string name="red_pin">Este lugar aún no tiene foto, ¡ve y toma una!</string>
<string name="green_pin">Este lugar ya tiene una foto.</string> <string name="green_pin">Este lugar ya tiene una foto.</string>
<string name="grey_pin">Ahora comprobando si este lugar tiene una foto.</string> <string name="grey_pin">Ahora comprobando si este lugar tiene una foto.</string>
<string name="error_while_loading">Error al cargar</string>
<string name="no_usages_found">No se encontraron usos</string>
<string name="usages_on_commons_heading">Commons</string>
<string name="usages_on_other_wikis_heading">Otras wikis</string>
<string name="file_usages_container_heading">Usos de archivos</string>
<string name="title_activity_single_web_view">Actividad de vista web única</string>
<string name="account">Cuenta</string>
<string name="vanish_account">Desaparecer cuenta</string>
<string name="account_vanish_request_confirm_title">Advertencia sobre la desaparición de la cuenta</string>
<string name="account_vanish_request_confirm">La desaparición de una cuenta en Wikimedia Commons es un &lt;b&gt;último recurso&lt;/b&gt; y &lt;b&gt;solo debe usarse cuando desee dejar de editar para siempre y también para ocultar la mayor cantidad posible de sus asociaciones pasadas.&lt;br/&gt;&lt;br/&gt;La desaparición de una cuenta en Wikimedia Commons se realiza cambiando el nombre de la cuenta para que otros no puedan reconocer sus contribuciones en un proceso llamado desaparición de la cuenta. &lt;b&gt;La desaparición de la cuenta no garantiza el anonimato completo ni elimina las contribuciones a los proyectos&lt;/b&gt;.</string>
<string name="caption">Leyenda</string>
<string name="caption_copied_to_clipboard">Leyenda copiado al portapapeles</string>
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Felicitaciones, todas las imágenes de este álbum han sido cargadas o marcadas como no para cargar.</string>
<string name="show_in_explore">Mostrar en Explorar</string>
<string name="show_in_nearby">Mostrar en las cercanías</string>
<string name="image_tag_line_created_and_uploaded_by">Creado y cargado por: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">Creado por %1$s y cargado por %2$s</string>
</resources> </resources>

View file

@ -386,7 +386,7 @@
<string name="deletion_reason_bad_for_my_privacy">فهمیدم که این برای حریم خصوصی من بد است.</string> <string name="deletion_reason_bad_for_my_privacy">فهمیدم که این برای حریم خصوصی من بد است.</string>
<string name="deletion_reason_no_longer_want_public">من تغییر عقیده دادم، نمی‌خواهم دیگر برای همه قابل‌مشاهده باشد.</string> <string name="deletion_reason_no_longer_want_public">من تغییر عقیده دادم، نمی‌خواهم دیگر برای همه قابل‌مشاهده باشد.</string>
<string name="deletion_reason_not_interesting">با پوزش، این تصویر برای یک دانشنامه مناسب نیست</string> <string name="deletion_reason_not_interesting">با پوزش، این تصویر برای یک دانشنامه مناسب نیست</string>
<string name="uploaded_by_myself">بارگذاری‌شده توسط خودم در %1$s؛ استفاده‌شده در %2$d مقاله.</string> <string name="uploaded_by_myself">بارگذاری‌شده توسط خودم در %1$s؛ استفاده‌شده در دست کم %2$d مقاله.</string>
<string name="no_uploads">به ویکی‌انبار خوش آمدید!\n\nاولین فایلتان را با فشردن کلید اضافه بارگذاری کنید.</string> <string name="no_uploads">به ویکی‌انبار خوش آمدید!\n\nاولین فایلتان را با فشردن کلید اضافه بارگذاری کنید.</string>
<string name="no_categories_selected">رده‌ای انتخاب نشده است</string> <string name="no_categories_selected">رده‌ای انتخاب نشده است</string>
<string name="no_categories_selected_warning_desc">تصاویر بدون رده به ندرت قابل‌استفاده هستند. آیا مطمئنید که می‌خواهید بدون انتخاب رده ادامه دهید؟</string> <string name="no_categories_selected_warning_desc">تصاویر بدون رده به ندرت قابل‌استفاده هستند. آیا مطمئنید که می‌خواهید بدون انتخاب رده ادامه دهید؟</string>
@ -508,4 +508,5 @@
<string name="your_feedback">بازخورد شما</string> <string name="your_feedback">بازخورد شما</string>
<string name="see_your_achievements">دستاوردهای خود را ببینید</string> <string name="see_your_achievements">دستاوردهای خود را ببینید</string>
<string name="could_not_load_place_data">ناتوان از بارگیری داده‌های مکانی</string> <string name="could_not_load_place_data">ناتوان از بارگیری داده‌های مکانی</string>
<string name="nominated_for_deletion_btn">نامزدشده برای حذف</string>
</resources> </resources>

View file

@ -180,7 +180,7 @@
<string name="tutorial_4_subtext_2">Kuvaus: Sydneyn oopperatalo lahden toiselta puolelta katsottuna</string> <string name="tutorial_4_subtext_2">Kuvaus: Sydneyn oopperatalo lahden toiselta puolelta katsottuna</string>
<string name="tutorial_4_subtext_3">Luokat: Sydneyn oopperatalo lännestä katsottuna, Sydneyn oopperatalo kaukaa katsottuna</string> <string name="tutorial_4_subtext_3">Luokat: Sydneyn oopperatalo lännestä katsottuna, Sydneyn oopperatalo kaukaa katsottuna</string>
<string name="welcome_wikipedia_text">Herätä Wikipedia-artikkelit eloon kuvillasi! Tuo kuvasi Wikipediaan.</string> <string name="welcome_wikipedia_text">Herätä Wikipedia-artikkelit eloon kuvillasi! Tuo kuvasi Wikipediaan.</string>
<string name="welcome_wikipedia_subtext">Wikipedian kuvat tulevat Wikimedia Commonsista.</string> <string name="welcome_wikipedia_subtext">Wikipedian kuvat ovat peräisin Wikimedia Commonsista.</string>
<string name="welcome_copyright_text">Kuvasi auttavat useita ihmisiä ympäri maailmaa artikkeleiden ymmärtämisessä.</string> <string name="welcome_copyright_text">Kuvasi auttavat useita ihmisiä ympäri maailmaa artikkeleiden ymmärtämisessä.</string>
<string name="welcome_copyright_subtext">Vältä tekijänoikeuksien alaista materiaalia, kuten julisteita, kirjan kansia ja useimpia Internetistä löydettyjä kuvia.</string> <string name="welcome_copyright_subtext">Vältä tekijänoikeuksien alaista materiaalia, kuten julisteita, kirjan kansia ja useimpia Internetistä löydettyjä kuvia.</string>
<string name="welcome_final_text">Luuletko ymmärtäneesi tämän?</string> <string name="welcome_final_text">Luuletko ymmärtäneesi tämän?</string>
@ -404,7 +404,7 @@
<string name="deletion_reason_bad_for_my_privacy">Huomasin, että se on haitallinen yksityisyydelleni.</string> <string name="deletion_reason_bad_for_my_privacy">Huomasin, että se on haitallinen yksityisyydelleni.</string>
<string name="deletion_reason_no_longer_want_public">Muutin mieleni, en halua että se on enää julkisesti näkyvissä.</string> <string name="deletion_reason_no_longer_want_public">Muutin mieleni, en halua että se on enää julkisesti näkyvissä.</string>
<string name="deletion_reason_not_interesting">Valitettavasti tämä kuva ei ole kiinnostava tietosanakirjaan</string> <string name="deletion_reason_not_interesting">Valitettavasti tämä kuva ei ole kiinnostava tietosanakirjaan</string>
<string name="uploaded_by_myself">Minä olen ladannut kohteen %1$s käytetty %2$d artikkelissa.</string> <string name="uploaded_by_myself" fuzzy="true">Minä olen ladannut kohteen %1$s käytetty %2$d artikkelissa.</string>
<string name="no_uploads">Tervetuloa Commonsiin!\n\nTallenna ensimmäinen mediasi koskettamalla lisäyspainiketta.</string> <string name="no_uploads">Tervetuloa Commonsiin!\n\nTallenna ensimmäinen mediasi koskettamalla lisäyspainiketta.</string>
<string name="no_categories_selected">Luokkia ei valittu</string> <string name="no_categories_selected">Luokkia ei valittu</string>
<string name="no_categories_selected_warning_desc">Kuvat, jotka eivät ole luokissa, ovat harvoin käyttökelpoisia. Haluatko varmasti jatkaa valitsematta luokkia?</string> <string name="no_categories_selected_warning_desc">Kuvat, jotka eivät ole luokissa, ovat harvoin käyttökelpoisia. Haluatko varmasti jatkaa valitsematta luokkia?</string>

View file

@ -457,7 +457,7 @@
<string name="deletion_reason_bad_for_my_privacy">Jai pensé que ce nétait pas bon pour ma vie privée</string> <string name="deletion_reason_bad_for_my_privacy">Jai pensé que ce nétait pas bon pour ma vie privée</string>
<string name="deletion_reason_no_longer_want_public">Jai changé d\'avis, je ne désire plus que cel soit visible publiquement</string> <string name="deletion_reason_no_longer_want_public">Jai changé d\'avis, je ne désire plus que cel soit visible publiquement</string>
<string name="deletion_reason_not_interesting">Désolé mais cette image nest pas intéressante pour une encyclopédie</string> <string name="deletion_reason_not_interesting">Désolé mais cette image nest pas intéressante pour une encyclopédie</string>
<string name="uploaded_by_myself">Téléversé par moi-même le %1$s, utilisé dans %2$d article(s).</string> <string name="uploaded_by_myself">Téléversé par moi-même le %1$s, utilisé dans au moins %2$d article(s).</string>
<string name="no_uploads">Bienvenue sur Commons!\n\nTéléversez votre premier média en tapant sur le bouton Ajouter.</string> <string name="no_uploads">Bienvenue sur Commons!\n\nTéléversez votre premier média en tapant sur le bouton Ajouter.</string>
<string name="no_categories_selected">Aucune catégorie sélectionnée</string> <string name="no_categories_selected">Aucune catégorie sélectionnée</string>
<string name="no_categories_selected_warning_desc">Les images sans catégories sont rarement utilisables. Voulez-vous vraiment continuer sans sélectionner des catégories appropriées?</string> <string name="no_categories_selected_warning_desc">Les images sans catégories sont rarement utilisables. Voulez-vous vraiment continuer sans sélectionner des catégories appropriées?</string>
@ -622,6 +622,8 @@
<string name="title_for_media">MÉDIA</string> <string name="title_for_media">MÉDIA</string>
<string name="title_for_child_classes">CLASSES ENFANTS</string> <string name="title_for_child_classes">CLASSES ENFANTS</string>
<string name="title_for_parent_classes">CLASSES PARENTES</string> <string name="title_for_parent_classes">CLASSES PARENTES</string>
<string name="title_for_subcategories">SOUS-CATÉGORIES</string>
<string name="title_for_parent_categories">CATÉGORIES PARENTES</string>
<string name="upload_nearby_place_found_title">Lieu à proximité trouvé</string> <string name="upload_nearby_place_found_title">Lieu à proximité trouvé</string>
<string name="upload_nearby_place_found_description_plural">Ces images sont-elles de %1$s?</string> <string name="upload_nearby_place_found_description_plural">Ces images sont-elles de %1$s?</string>
<string name="upload_nearby_place_found_description_singular">Est-ce une image de %1$s?</string> <string name="upload_nearby_place_found_description_singular">Est-ce une image de %1$s?</string>
@ -869,4 +871,5 @@
<string name="show_in_nearby">Afficher à proximité</string> <string name="show_in_nearby">Afficher à proximité</string>
<string name="image_tag_line_created_and_uploaded_by">Crée et publiée par: %1$s</string> <string name="image_tag_line_created_and_uploaded_by">Crée et publiée par: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">Créé par %1$s et publiée par %2$s</string> <string name="image_tag_line_created_by_and_uploaded_by">Créé par %1$s et publiée par %2$s</string>
<string name="nominated_for_deletion_btn">Nommé pour suppression</string>
</resources> </resources>

View file

@ -394,7 +394,7 @@
<string name="deletion_reason_bad_for_my_privacy">Decateime de que prexudica a miña privacidade</string> <string name="deletion_reason_bad_for_my_privacy">Decateime de que prexudica a miña privacidade</string>
<string name="deletion_reason_no_longer_want_public">Cambiei de idea, non quero que siga sendo visible de forma pública</string> <string name="deletion_reason_no_longer_want_public">Cambiei de idea, non quero que siga sendo visible de forma pública</string>
<string name="deletion_reason_not_interesting">Desculpas, esta imaxe non é interesante para unha enciclopedia</string> <string name="deletion_reason_not_interesting">Desculpas, esta imaxe non é interesante para unha enciclopedia</string>
<string name="uploaded_by_myself">Cargada por min o %1$s, usada en %2$d artigo(s).</string> <string name="uploaded_by_myself" fuzzy="true">Cargada por min o %1$s, usada en %2$d artigo(s).</string>
<string name="no_uploads">Dámoslle a benvida ó Commonsǃ\n\nCargue o seu primeiro ficheiro premendo no botón Engadir.</string> <string name="no_uploads">Dámoslle a benvida ó Commonsǃ\n\nCargue o seu primeiro ficheiro premendo no botón Engadir.</string>
<string name="no_categories_selected">Non hai categorías seleccionadas</string> <string name="no_categories_selected">Non hai categorías seleccionadas</string>
<string name="no_categories_selected_warning_desc">As imaxes sen categorías só son utilizables en contadas ocasións. Está seguro de que quere continuar sen seleccionar categorías?</string> <string name="no_categories_selected_warning_desc">As imaxes sen categorías só son utilizables en contadas ocasións. Está seguro de que quere continuar sen seleccionar categorías?</string>

View file

@ -108,6 +108,7 @@
<string name="menu_from_camera">फ़ोटो लें</string> <string name="menu_from_camera">फ़ोटो लें</string>
<string name="menu_nearby">आसपास</string> <string name="menu_nearby">आसपास</string>
<string name="provider_contributions">मेरे अपलोड</string> <string name="provider_contributions">मेरे अपलोड</string>
<string name="menu_copy_link">लिंक कॉपी करें</string>
<string name="menu_share">साझा करें</string> <string name="menu_share">साझा करें</string>
<string name="share_title_hint" fuzzy="true">शीर्षक (आवश्यक)</string> <string name="share_title_hint" fuzzy="true">शीर्षक (आवश्यक)</string>
<string name="share_description_hint">विवरण</string> <string name="share_description_hint">विवरण</string>
@ -125,7 +126,7 @@
<string name="menu_save_categories">सहेजें</string> <string name="menu_save_categories">सहेजें</string>
<string name="refresh_button">ताजा करें</string> <string name="refresh_button">ताजा करें</string>
<string name="display_list_button">सूची</string> <string name="display_list_button">सूची</string>
<string name="contributions_subtitle_zero" fuzzy="true">अभी तक कोई अपलोड नहीं</string> <string name="contributions_subtitle_zero">(अभी तक कोई अपलोड नहीं)</string>
<string name="categories_not_found">%1$s से कोई श्रेणी मेल नहीं खाती</string> <string name="categories_not_found">%1$s से कोई श्रेणी मेल नहीं खाती</string>
<string name="categories_skip_explanation">विकिमीडिया कॉमन्स पर अपनी छवियों को अधिक खोजने योग्य बनाने के लिए श्रेणियां जोड़ें|\nश्रेणियां जोड़ने के लिए टाइप करना प्रारंभ करें|</string> <string name="categories_skip_explanation">विकिमीडिया कॉमन्स पर अपनी छवियों को अधिक खोजने योग्य बनाने के लिए श्रेणियां जोड़ें|\nश्रेणियां जोड़ने के लिए टाइप करना प्रारंभ करें|</string>
<string name="categories_activity_title">श्रेणियाँ</string> <string name="categories_activity_title">श्रेणियाँ</string>
@ -179,7 +180,7 @@
<string name="welcome_copyright_subtext">इंटरनेट से मिली कोई कॉपीराइट सामग्री के साथ साथ पोस्टर, पुस्तक के खड्डे आदि को भी अपलोड करने से बचें।</string> <string name="welcome_copyright_subtext">इंटरनेट से मिली कोई कॉपीराइट सामग्री के साथ साथ पोस्टर, पुस्तक के खड्डे आदि को भी अपलोड करने से बचें।</string>
<string name="welcome_final_text">क्या आपको लगता है कि आप समझ गए?</string> <string name="welcome_final_text">क्या आपको लगता है कि आप समझ गए?</string>
<string name="welcome_final_button_text">हाँ!</string> <string name="welcome_final_button_text">हाँ!</string>
<string name="welcome_help_button_text" fuzzy="true">&lt;u&gt;अधिक जानकारी&lt;/u&gt;</string> <string name="welcome_help_button_text">अधिक जानकारी</string>
<string name="detail_panel_cats_label">श्रेणियाँ</string> <string name="detail_panel_cats_label">श्रेणियाँ</string>
<string name="detail_panel_cats_loading">लोड हो रहा है…</string> <string name="detail_panel_cats_loading">लोड हो रहा है…</string>
<string name="detail_panel_cats_none">कुछ चयनित नहीं</string> <string name="detail_panel_cats_none">कुछ चयनित नहीं</string>
@ -193,7 +194,9 @@
<string name="upload">अपलोड करें</string> <string name="upload">अपलोड करें</string>
<string name="yes">हाँ</string> <string name="yes">हाँ</string>
<string name="no">नहीं</string> <string name="no">नहीं</string>
<string name="media_detail_caption">कैप्शन</string>
<string name="media_detail_title">शीर्षक</string> <string name="media_detail_title">शीर्षक</string>
<string name="media_detail_depiction">चित्रण</string>
<string name="media_detail_description">विवरण</string> <string name="media_detail_description">विवरण</string>
<string name="media_detail_discussion">चर्चा</string> <string name="media_detail_discussion">चर्चा</string>
<string name="media_detail_author">लेखक</string> <string name="media_detail_author">लेखक</string>
@ -258,11 +261,11 @@
<string name="wikicode_copied">विकिटेक्सट क्लिपबोर्ड पर कॉपी किया जा चुका है</string> <string name="wikicode_copied">विकिटेक्सट क्लिपबोर्ड पर कॉपी किया जा चुका है</string>
<string name="nearby_location_not_available">स्थान उपलब्ध नहीं है।</string> <string name="nearby_location_not_available">स्थान उपलब्ध नहीं है।</string>
<string name="location_permission_rationale_nearby">आसपास के स्थान दिखाने के लिए अनुमति चाहिए</string> <string name="location_permission_rationale_nearby">आसपास के स्थान दिखाने के लिए अनुमति चाहिए</string>
<string name="nearby_directions" fuzzy="true">दिशा-निर्देश</string> <string name="nearby_directions">दिशा-निर्देश</string>
<string name="nearby_wikidata" fuzzy="true">विकीडाटा</string> <string name="nearby_wikidata">विकीडाटा</string>
<string name="nearby_wikipedia" fuzzy="true">विकीपीडिया</string> <string name="nearby_wikipedia">विकीपीडिया</string>
<string name="nearby_commons">कॉमन्स</string> <string name="nearby_commons">कॉमन्स</string>
<string name="about_rate_us" fuzzy="true">&lt;u&gt;हमें रेट करें&lt;/u&gt;</string> <string name="about_rate_us">हमें रेट करें</string>
<string name="about_faq">अक्सर पूछे जाने वाले प्रश्न</string> <string name="about_faq">अक्सर पूछे जाने वाले प्रश्न</string>
<string name="welcome_skip_button">प्रशिक्षण छोड़ें</string> <string name="welcome_skip_button">प्रशिक्षण छोड़ें</string>
<string name="no_internet">इंटरनेट उपलब्ध नहीं</string> <string name="no_internet">इंटरनेट उपलब्ध नहीं</string>
@ -276,6 +279,7 @@
<string name="no_images_found">कोई चित्र नहीं मिला!</string> <string name="no_images_found">कोई चित्र नहीं मिला!</string>
<string name="error_loading_images">चित्र अपलोड करते समय त्रुटि उत्पन्न हुई।</string> <string name="error_loading_images">चित्र अपलोड करते समय त्रुटि उत्पन्न हुई।</string>
<string name="image_uploaded_by">अपलोड: %1$s</string> <string name="image_uploaded_by">अपलोड: %1$s</string>
<string name="block_notification_title">अवरोधित</string>
<string name="block_notification">कॉमन्स पर सम्पादन से आप अवरोधित हो चुके हैं</string> <string name="block_notification">कॉमन्स पर सम्पादन से आप अवरोधित हो चुके हैं</string>
<string name="app_widget_heading">आज का चित्र</string> <string name="app_widget_heading">आज का चित्र</string>
<string name="menu_search_button">खोजें</string> <string name="menu_search_button">खोजें</string>
@ -286,6 +290,7 @@
<string name="error_loading_categories">श्रेणी लोड करते समय त्रुटि उत्पन्न हुई।</string> <string name="error_loading_categories">श्रेणी लोड करते समय त्रुटि उत्पन्न हुई।</string>
<string name="search_tab_title_media">मीडिया</string> <string name="search_tab_title_media">मीडिया</string>
<string name="search_tab_title_categories">श्रेणियाँ</string> <string name="search_tab_title_categories">श्रेणियाँ</string>
<string name="search_tab_title_depictions">आयटम</string>
<string name="explore_tab_title_featured">निर्वाचित</string> <string name="explore_tab_title_featured">निर्वाचित</string>
<string name="explore_tab_title_map">नक्शा</string> <string name="explore_tab_title_map">नक्शा</string>
<string name="successful_wikidata_edit" fuzzy="true">चित्र सफ़लतापूर्वक विकिडाटा के %1$s पर सफलतापूर्वक जोड़ दिया गया है।</string> <string name="successful_wikidata_edit" fuzzy="true">चित्र सफ़लतापूर्वक विकिडाटा के %1$s पर सफलतापूर्वक जोड़ दिया गया है।</string>
@ -312,10 +317,12 @@
<string name="nominate_delete">हटाने के लिये नामांकन करें</string> <string name="nominate_delete">हटाने के लिये नामांकन करें</string>
<string name="delete">हटाएँ</string> <string name="delete">हटाएँ</string>
<string name="Achievements">उपलब्धियाँ</string> <string name="Achievements">उपलब्धियाँ</string>
<string name="Profile">प्रोफ़ाइल</string>
<string name="statistics">सांख्यिकी</string> <string name="statistics">सांख्यिकी</string>
<string name="statistics_thanks">धन्यवाद प्राप्त किया</string> <string name="statistics_thanks">धन्यवाद प्राप्त किया</string>
<string name="statistics_featured">निर्वाचित चित्र</string> <string name="statistics_featured">निर्वाचित चित्र</string>
<string name="level">स्तर %d</string> <string name="level">स्तर %d</string>
<string name="profileLevel">%s (स्तर %s )</string>
<string name="images_uploaded">चित्र अपलोड हुआ</string> <string name="images_uploaded">चित्र अपलोड हुआ</string>
<string name="image_reverts">चित्रों को वापस नहीं किया गया</string> <string name="image_reverts">चित्रों को वापस नहीं किया गया</string>
<string name="images_used_by_wiki">उपयोग हुए चित्र</string> <string name="images_used_by_wiki">उपयोग हुए चित्र</string>
@ -353,7 +360,10 @@
<string name="ends_on">खत्म होगा:</string> <string name="ends_on">खत्म होगा:</string>
<string name="display_campaigns">दृश्य अभियान</string> <string name="display_campaigns">दृश्य अभियान</string>
<string name="display_campaigns_explanation" fuzzy="true">वर्तमान में चल रहे अभियानों को जानने के लिये यहाँ दबायें</string> <string name="display_campaigns_explanation" fuzzy="true">वर्तमान में चल रहे अभियानों को जानने के लिये यहाँ दबायें</string>
<string name="option_allow">अनुमति दें</string>
<string name="option_dismiss">रद्द करें</string>
<string name="error_processing_image">छवि संसाधित करते समय त्रुटि आई। कृपया पुन: प्रयास करें!</string> <string name="error_processing_image">छवि संसाधित करते समय त्रुटि आई। कृपया पुन: प्रयास करें!</string>
<string name="nominate_for_deletion_done">पूर्ण हुआ</string>
<string name="no_image">कोई चित्र उपयोग नहीं हुआ</string> <string name="no_image">कोई चित्र उपयोग नहीं हुआ</string>
<string name="no_image_reverted">कोई चित्र वापस नहीं लाया</string> <string name="no_image_reverted">कोई चित्र वापस नहीं लाया</string>
<string name="no_image_uploaded">कोई चित्र अपलोड नहीं किया</string> <string name="no_image_uploaded">कोई चित्र अपलोड नहीं किया</string>

View file

@ -362,7 +362,7 @@
<string name="deletion_reason_bad_for_my_privacy">Észleltem, hogy ez rossz a magánszférámnak</string> <string name="deletion_reason_bad_for_my_privacy">Észleltem, hogy ez rossz a magánszférámnak</string>
<string name="deletion_reason_no_longer_want_public">Meggondoltam magam, nem szeretném, hogy nyilvánosan látható legyen</string> <string name="deletion_reason_no_longer_want_public">Meggondoltam magam, nem szeretném, hogy nyilvánosan látható legyen</string>
<string name="deletion_reason_not_interesting">Sajnos ez a fénykép nem érdekes egy enciklopédia számára</string> <string name="deletion_reason_not_interesting">Sajnos ez a fénykép nem érdekes egy enciklopédia számára</string>
<string name="uploaded_by_myself">Feltöltve ekkorː %1$s, %2$d cikkben használva.</string> <string name="uploaded_by_myself" fuzzy="true">Feltöltve ekkorː %1$s, %2$d cikkben használva.</string>
<string name="no_uploads">Üdvözlünk a Commons-ban. \n\nA hozzáadás gombra koppintva feltöltheted első képedet.</string> <string name="no_uploads">Üdvözlünk a Commons-ban. \n\nA hozzáadás gombra koppintva feltöltheted első képedet.</string>
<string name="no_categories_selected">Nincs kiválasztott kategória</string> <string name="no_categories_selected">Nincs kiválasztott kategória</string>
<string name="no_categories_selected_warning_desc">A kategória nélküli képek ritkán használhatóak. Biztos, hogy kategória kiválasztása nélkül akarsz továbblépni?</string> <string name="no_categories_selected_warning_desc">A kategória nélküli képek ritkán használhatóak. Biztos, hogy kategória kiválasztása nélkül akarsz továbblépni?</string>

View file

@ -112,6 +112,7 @@
<string name="login_failed_throttled">Troppo de tentativas fallite. Per favor reproba in alcun minutas.</string> <string name="login_failed_throttled">Troppo de tentativas fallite. Per favor reproba in alcun minutas.</string>
<string name="login_failed_blocked">Iste usator ha essite blocate sur Commons</string> <string name="login_failed_blocked">Iste usator ha essite blocate sur Commons</string>
<string name="login_failed_2fa_needed">Tu debe fornir tu codice de authentication bifactorial.</string> <string name="login_failed_2fa_needed">Tu debe fornir tu codice de authentication bifactorial.</string>
<string name="login_failed_email_auth_needed">Un codice de verification de session ha essite inviate a tu adresse de e-mail. Per favor insere iste codice pro aperir session.</string>
<string name="login_failed_generic">Apertura de session fallite</string> <string name="login_failed_generic">Apertura de session fallite</string>
<string name="share_upload_button">Incargar</string> <string name="share_upload_button">Incargar</string>
<string name="multiple_share_base_title">Nomine de iste insimul</string> <string name="multiple_share_base_title">Nomine de iste insimul</string>
@ -212,6 +213,7 @@
<string name="become_a_tester_title">Devenir testator beta</string> <string name="become_a_tester_title">Devenir testator beta</string>
<string name="become_a_tester_description">Abona te a nostre canal beta sur Google Play e sia le prime a ganiar accesso a nove functiones e correctiones de anomalias</string> <string name="become_a_tester_description">Abona te a nostre canal beta sur Google Play e sia le prime a ganiar accesso a nove functiones e correctiones de anomalias</string>
<string name="_2fa_code">Codice 2FA</string> <string name="_2fa_code">Codice 2FA</string>
<string name="email_auth_code">Codice de verification in e-mail</string>
<string name="logout_verification">Vole tu vermente clauder session?</string> <string name="logout_verification">Vole tu vermente clauder session?</string>
<string name="mediaimage_failed">Imagine multimedial fallite</string> <string name="mediaimage_failed">Imagine multimedial fallite</string>
<string name="no_subcategory_found">Necun subcategoria trovate</string> <string name="no_subcategory_found">Necun subcategoria trovate</string>
@ -405,7 +407,7 @@
<string name="deletion_reason_bad_for_my_privacy">Io ha comprendite que es mal pro mi vita private</string> <string name="deletion_reason_bad_for_my_privacy">Io ha comprendite que es mal pro mi vita private</string>
<string name="deletion_reason_no_longer_want_public">Io ha cambiate de idea, io non vole plus que illo sia publicamente visibile</string> <string name="deletion_reason_no_longer_want_public">Io ha cambiate de idea, io non vole plus que illo sia publicamente visibile</string>
<string name="deletion_reason_not_interesting">Iste imagine non es interessante pro un encyclopedia</string> <string name="deletion_reason_not_interesting">Iste imagine non es interessante pro un encyclopedia</string>
<string name="uploaded_by_myself">Incargate per me mesme le %1$s, usate in %2$d articulo(s).</string> <string name="uploaded_by_myself">Incargate per me mesme le %1$s, usate al minus in %2$d articulo(s).</string>
<string name="no_uploads">Benvenite a Commons!\n\nPro incargar tu prime file multimedial, tocca le button Adder.</string> <string name="no_uploads">Benvenite a Commons!\n\nPro incargar tu prime file multimedial, tocca le button Adder.</string>
<string name="no_categories_selected">Necun categoria seligite</string> <string name="no_categories_selected">Necun categoria seligite</string>
<string name="no_categories_selected_warning_desc">Imagines sin categorias es rarmente usabile. Es tu secur de voler continuar sin seliger categorias?</string> <string name="no_categories_selected_warning_desc">Imagines sin categorias es rarmente usabile. Es tu secur de voler continuar sin seliger categorias?</string>
@ -570,6 +572,8 @@
<string name="title_for_media">MULTIMEDIA</string> <string name="title_for_media">MULTIMEDIA</string>
<string name="title_for_child_classes">CLASSES FILIO</string> <string name="title_for_child_classes">CLASSES FILIO</string>
<string name="title_for_parent_classes">CLASSES GENITOR</string> <string name="title_for_parent_classes">CLASSES GENITOR</string>
<string name="title_for_subcategories">SUBCATEGORIAS</string>
<string name="title_for_parent_categories">CATEGORIAS GENITOR</string>
<string name="upload_nearby_place_found_title">Loco a proximitate trovate</string> <string name="upload_nearby_place_found_title">Loco a proximitate trovate</string>
<string name="upload_nearby_place_found_description_plural">Es istes imagines de %1$s?</string> <string name="upload_nearby_place_found_description_plural">Es istes imagines de %1$s?</string>
<string name="upload_nearby_place_found_description_singular">Es isto un imagine de %1$s?</string> <string name="upload_nearby_place_found_description_singular">Es isto un imagine de %1$s?</string>
@ -775,6 +779,7 @@
<string name="talk">Discussion</string> <string name="talk">Discussion</string>
<string name="write_something_about_the_item">Scribe qualcosa sur le elemento %1$s. Isto essera visibile publicamente.</string> <string name="write_something_about_the_item">Scribe qualcosa sur le elemento %1$s. Isto essera visibile publicamente.</string>
<string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">%1$s non existe plus, necun imagine pote jammais esser prendite de illo.</string> <string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">%1$s non existe plus, necun imagine pote jammais esser prendite de illo.</string>
<string name="is_at_a_different_place_wikidata">%1$s se trova in un altere loco.</string>
<string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">%1$s es in un altere loco. Per favor specifica le loco correcte hic infra, e si possibile, indica le latitude e longitude correcte.</string> <string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">%1$s es in un altere loco. Per favor specifica le loco correcte hic infra, e si possibile, indica le latitude e longitude correcte.</string>
<string name="other_problem_or_information_please_explain_below">Altere problema o information (per favor explica hic infra).</string> <string name="other_problem_or_information_please_explain_below">Altere problema o information (per favor explica hic infra).</string>
<string name="feedback_destination_note">Tu retroaction apparera sur le sequente pagina wiki: &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\"&gt;Commons:Mobile app/Feedback&lt;/a&gt;</string> <string name="feedback_destination_note">Tu retroaction apparera sur le sequente pagina wiki: &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\"&gt;Commons:Mobile app/Feedback&lt;/a&gt;</string>
@ -801,4 +806,17 @@
<string name="usages_on_commons_heading">Commons</string> <string name="usages_on_commons_heading">Commons</string>
<string name="usages_on_other_wikis_heading">Altere wikis</string> <string name="usages_on_other_wikis_heading">Altere wikis</string>
<string name="file_usages_container_heading">Usos del file</string> <string name="file_usages_container_heading">Usos del file</string>
<string name="title_activity_single_web_view">Activitate de singule visita web</string>
<string name="account">Conto</string>
<string name="vanish_account">Facer disparer le conto</string>
<string name="account_vanish_request_confirm_title">Advertimento concernente le disparition del conto</string>
<string name="account_vanish_request_confirm">Le disparition es un &lt;b&gt;ultime recurso&lt;/b&gt; e debe &lt;b&gt;solmente esser usate quando tu vole cessar de modificar pro sempre&lt;/b&gt; e celar le maximo possibile de tu associationes anterior.&lt;br/&gt;&lt;br/&gt;Le deletion del conto sur Wikipedia se effectua cambiante tu nomine de conto de maniera que alteres non pote recognoscer tu contributiones. Iste processo se appella le disparition del conto. &lt;b&gt;Le disparition non garanti le anonymitate complete ni remove contributiones al projectos.&lt;/b&gt;</string>
<string name="caption">Legenda</string>
<string name="caption_copied_to_clipboard">Legenda copiate al area de transferentia</string>
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Felicitationes, tote le imagines in iste album ha essite incargate o marcate como non incargabile.</string>
<string name="show_in_explore">Monstrar in Explorar</string>
<string name="show_in_nearby">Monstrar in A proximitate</string>
<string name="image_tag_line_created_and_uploaded_by">Create e incargate per: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">Create per %1$s e incargate per %2$s</string>
<string name="nominated_for_deletion_btn">Nominate pro deletion</string>
</resources> </resources>

View file

@ -410,7 +410,7 @@
<string name="deletion_reason_bad_for_my_privacy">Saya menyadari itu buruk untuk privasi saya</string> <string name="deletion_reason_bad_for_my_privacy">Saya menyadari itu buruk untuk privasi saya</string>
<string name="deletion_reason_no_longer_want_public">Saya berubah pikiran, saya tidak ingin itu terlihat publik lagi</string> <string name="deletion_reason_no_longer_want_public">Saya berubah pikiran, saya tidak ingin itu terlihat publik lagi</string>
<string name="deletion_reason_not_interesting">Maaf gambar ini tidak menarik untuk ensiklopedia</string> <string name="deletion_reason_not_interesting">Maaf gambar ini tidak menarik untuk ensiklopedia</string>
<string name="uploaded_by_myself">Diunggah saya sendiri pada %1$s, digunakan dalam %2$d artikel.</string> <string name="uploaded_by_myself" fuzzy="true">Diunggah saya sendiri pada %1$s, digunakan dalam %2$d artikel.</string>
<string name="no_uploads">Unggah media pertama Anda dengan mengetuk tombol.</string> <string name="no_uploads">Unggah media pertama Anda dengan mengetuk tombol.</string>
<string name="no_categories_selected">Tidak ada Kategori yang Dipilih</string> <string name="no_categories_selected">Tidak ada Kategori yang Dipilih</string>
<string name="no_categories_selected_warning_desc">Gambar tanpa kategori jarang dapat digunakan. Apakah Anda yakin ingin mengirim tanpa memilih kategori?</string> <string name="no_categories_selected_warning_desc">Gambar tanpa kategori jarang dapat digunakan. Apakah Anda yakin ingin mengirim tanpa memilih kategori?</string>

View file

@ -410,7 +410,7 @@
<string name="deletion_reason_bad_for_my_privacy">Me konstatis ke ol esas mala por mea privateso</string> <string name="deletion_reason_bad_for_my_privacy">Me konstatis ke ol esas mala por mea privateso</string>
<string name="deletion_reason_no_longer_want_public">Me chanjis mea ideo: me ne pluse deziras ke ol esos publike videbla</string> <string name="deletion_reason_no_longer_want_public">Me chanjis mea ideo: me ne pluse deziras ke ol esos publike videbla</string>
<string name="deletion_reason_not_interesting">Pardonez! Ca imajo ne esas interesanta por ula enciklopedio</string> <string name="deletion_reason_not_interesting">Pardonez! Ca imajo ne esas interesanta por ula enciklopedio</string>
<string name="uploaded_by_myself">Adjuntita da me, che %1$s, uzita en %2$d artiklo/artikli.</string> <string name="uploaded_by_myself" fuzzy="true">Adjuntita da me, che %1$s, uzita en %2$d artiklo/artikli.</string>
<string name="no_uploads">Bonveno a Commons!\n\nSendez vua unesma arkivo kliktanta sur butono \"adjuntez\" (\'\'add\'\').</string> <string name="no_uploads">Bonveno a Commons!\n\nSendez vua unesma arkivo kliktanta sur butono \"adjuntez\" (\'\'add\'\').</string>
<string name="no_categories_selected">Nula kategorio selektita</string> <string name="no_categories_selected">Nula kategorio selektita</string>
<string name="no_categories_selected_warning_desc">Imaji sen kategorii rare esas uzebla. Ka vu fakte deziras sendar ol sen selektar irga kategorio?</string> <string name="no_categories_selected_warning_desc">Imaji sen kategorii rare esas uzebla. Ka vu fakte deziras sendar ol sen selektar irga kategorio?</string>

View file

@ -392,7 +392,7 @@
<string name="deletion_reason_bad_for_my_privacy">Ég áttaði mig á að þetta væri slæmt fyrir gagnaleynd mína</string> <string name="deletion_reason_bad_for_my_privacy">Ég áttaði mig á að þetta væri slæmt fyrir gagnaleynd mína</string>
<string name="deletion_reason_no_longer_want_public">Ég skipti um skoðun, ég vil ekki að hún sé lengur öllum sýnileg</string> <string name="deletion_reason_no_longer_want_public">Ég skipti um skoðun, ég vil ekki að hún sé lengur öllum sýnileg</string>
<string name="deletion_reason_not_interesting">Afsakið, þessi mynd hefur ekkert gildi fyrir alfræðirit</string> <string name="deletion_reason_not_interesting">Afsakið, þessi mynd hefur ekkert gildi fyrir alfræðirit</string>
<string name="uploaded_by_myself">Sent inn af mér sjálfum %1$s, notað í %2$d grein(um).</string> <string name="uploaded_by_myself" fuzzy="true">Sent inn af mér sjálfum %1$s, notað í %2$d grein(um).</string>
<string name="no_uploads">Velkomin í Commons!\n\nSendu inn fyrstu margmiðlunargögnin þín með því að ýta á viðbætingarhnappinn.</string> <string name="no_uploads">Velkomin í Commons!\n\nSendu inn fyrstu margmiðlunargögnin þín með því að ýta á viðbætingarhnappinn.</string>
<string name="no_categories_selected">Engir flokkar valdir</string> <string name="no_categories_selected">Engir flokkar valdir</string>
<string name="no_categories_selected_warning_desc">Myndir án flokka eru sjaldnast nýtilegar. Ertu viss um að þú viljir halda áfram án þess að velja flokka?</string> <string name="no_categories_selected_warning_desc">Myndir án flokka eru sjaldnast nýtilegar. Ertu viss um að þú viljir halda áfram án þess að velja flokka?</string>

View file

@ -143,6 +143,7 @@
<string name="categories_search_text_hint">Cerca categorie</string> <string name="categories_search_text_hint">Cerca categorie</string>
<string name="depicts_search_text_hint">Cerca elementi che il tuo file rappresenta (montagna, Taj Mahal, ecc.)</string> <string name="depicts_search_text_hint">Cerca elementi che il tuo file rappresenta (montagna, Taj Mahal, ecc.)</string>
<string name="menu_save_categories">Salva</string> <string name="menu_save_categories">Salva</string>
<string name="menu_overflow_desc">Menu overflow</string>
<string name="refresh_button">Aggiorna</string> <string name="refresh_button">Aggiorna</string>
<string name="display_list_button">Elenco</string> <string name="display_list_button">Elenco</string>
<string name="contributions_subtitle_zero">(Non è stato ancora caricato niente)</string> <string name="contributions_subtitle_zero">(Non è stato ancora caricato niente)</string>
@ -289,7 +290,7 @@
<string name="send_log_file_description">Invia il file di registro agli sviluppatori tramite email per aiutarli a risolvere i problemi con l\'applicazione. Nota: i log potrebbero contenere informazioni di identificazione</string> <string name="send_log_file_description">Invia il file di registro agli sviluppatori tramite email per aiutarli a risolvere i problemi con l\'applicazione. Nota: i log potrebbero contenere informazioni di identificazione</string>
<string name="no_web_browser">Nessun browser web trovato per aprire l\'URL</string> <string name="no_web_browser">Nessun browser web trovato per aprire l\'URL</string>
<string name="null_url">Errore! URL non trovato</string> <string name="null_url">Errore! URL non trovato</string>
<string name="nominate_deletion">Proponi per la Cancellazione</string> <string name="nominate_deletion">Proponi per la cancellazione</string>
<string name="nominated_for_deletion">Questa immagine è stata proposta per la cancellazione.</string> <string name="nominated_for_deletion">Questa immagine è stata proposta per la cancellazione.</string>
<string name="nominated_see_more">Vedi la pagina web per i dettagli</string> <string name="nominated_see_more">Vedi la pagina web per i dettagli</string>
<string name="skip_login">Salta</string> <string name="skip_login">Salta</string>
@ -433,7 +434,7 @@
<string name="deletion_reason_bad_for_my_privacy">Mi sono reso conto che viola la mia privacy</string> <string name="deletion_reason_bad_for_my_privacy">Mi sono reso conto che viola la mia privacy</string>
<string name="deletion_reason_no_longer_want_public">Ho cambiato idea, non voglio più che sia pubblicamente visibile</string> <string name="deletion_reason_no_longer_want_public">Ho cambiato idea, non voglio più che sia pubblicamente visibile</string>
<string name="deletion_reason_not_interesting">Spiacente, questa immagine non è interessante per un\'enciclopedia</string> <string name="deletion_reason_not_interesting">Spiacente, questa immagine non è interessante per un\'enciclopedia</string>
<string name="uploaded_by_myself">Caricato da me stesso il %1$s, utilizzato in %2$d voce/i.</string> <string name="uploaded_by_myself">Caricato da me stesso il %1$s, utilizzato almeno in %2$d voce/i.</string>
<string name="no_uploads">Benvenuto su Commons!\n\nCarica il tuo primo file multimediale toccando il pulsante aggiungi.</string> <string name="no_uploads">Benvenuto su Commons!\n\nCarica il tuo primo file multimediale toccando il pulsante aggiungi.</string>
<string name="no_categories_selected">Nessuna categoria selezionata</string> <string name="no_categories_selected">Nessuna categoria selezionata</string>
<string name="no_categories_selected_warning_desc">Le immagini senza categorie sono raramente utilizzabili. Sei sicuro di voler continuare senza selezionare le categorie?</string> <string name="no_categories_selected_warning_desc">Le immagini senza categorie sono raramente utilizzabili. Sei sicuro di voler continuare senza selezionare le categorie?</string>
@ -594,6 +595,7 @@
<string name="title_for_media">MEDIA</string> <string name="title_for_media">MEDIA</string>
<string name="title_for_child_classes">CLASSI FIGLIE</string> <string name="title_for_child_classes">CLASSI FIGLIE</string>
<string name="title_for_parent_classes">CLASSI SUPERIORI</string> <string name="title_for_parent_classes">CLASSI SUPERIORI</string>
<string name="title_for_subcategories">Sottocategorie</string>
<string name="upload_nearby_place_found_title">Rinvenuto luogo nei pressi</string> <string name="upload_nearby_place_found_title">Rinvenuto luogo nei pressi</string>
<string name="upload_nearby_place_found_description_plural">Queste sono immagini di %1$s?</string> <string name="upload_nearby_place_found_description_plural">Queste sono immagini di %1$s?</string>
<string name="upload_nearby_place_found_description_singular">Questa è un\'immagine di %1$s?</string> <string name="upload_nearby_place_found_description_singular">Questa è un\'immagine di %1$s?</string>
@ -771,7 +773,7 @@
<string name="learn_how_to_write_a_useful_caption">Impara come scrivere una didascalia utile</string> <string name="learn_how_to_write_a_useful_caption">Impara come scrivere una didascalia utile</string>
<string name="see_your_achievements">Vedi i tuoi risultati</string> <string name="see_your_achievements">Vedi i tuoi risultati</string>
<string name="edit_image">Modifica Immagine</string> <string name="edit_image">Modifica Immagine</string>
<string name="edit_location">Modifica Posizione</string> <string name="edit_location">Modifica posizione</string>
<string name="location_updated">Posizione aggiornata!</string> <string name="location_updated">Posizione aggiornata!</string>
<string name="remove_location">Rimuovi posizione</string> <string name="remove_location">Rimuovi posizione</string>
<string name="remove_location_warning_title">Rimuovi avviso di posizione</string> <string name="remove_location_warning_title">Rimuovi avviso di posizione</string>
@ -836,4 +838,5 @@
<string name="show_in_nearby">Mostra nelle vicinanze</string> <string name="show_in_nearby">Mostra nelle vicinanze</string>
<string name="image_tag_line_created_and_uploaded_by">Creato e caricato da: %1$s</string> <string name="image_tag_line_created_and_uploaded_by">Creato e caricato da: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">Creato da %1$s e caricato da %2$s</string> <string name="image_tag_line_created_by_and_uploaded_by">Creato da %1$s e caricato da %2$s</string>
<string name="nominated_for_deletion_btn">Proposto per la cancellazione</string>
</resources> </resources>

View file

@ -444,7 +444,7 @@
<string name="deletion_reason_bad_for_my_privacy">הבנתי שזה לא טוב לפרטיות שלי</string> <string name="deletion_reason_bad_for_my_privacy">הבנתי שזה לא טוב לפרטיות שלי</string>
<string name="deletion_reason_no_longer_want_public">התחרטתי, אינני רוצה עוד שהיא תוצג לציבור</string> <string name="deletion_reason_no_longer_want_public">התחרטתי, אינני רוצה עוד שהיא תוצג לציבור</string>
<string name="deletion_reason_not_interesting">סליחה, התמונה אינה מעניינת עבור אנציקלופדיה</string> <string name="deletion_reason_not_interesting">סליחה, התמונה אינה מעניינת עבור אנציקלופדיה</string>
<string name="uploaded_by_myself">הועלה על ידי ב-%1$s, בשימוש ב-%2$d מאמר(ים)</string> <string name="uploaded_by_myself">הועלה על ידי ב־%1$s, בשימוש ב־%2$d ערכים לפחות.</string>
<string name="no_uploads">ברוך בואך לוויקישיתוף!\n\nכדי להעלות את המדיה הראשונה שלך, נא להקיש על כפתור ההוספה.</string> <string name="no_uploads">ברוך בואך לוויקישיתוף!\n\nכדי להעלות את המדיה הראשונה שלך, נא להקיש על כפתור ההוספה.</string>
<string name="no_categories_selected">לא נבחרו קטגוריות</string> <string name="no_categories_selected">לא נבחרו קטגוריות</string>
<string name="no_categories_selected_warning_desc">תמונות ללא קטגוריות בדרך כלל אינן שימושיות. להמשיך ללא בחירת קטגוריות?</string> <string name="no_categories_selected_warning_desc">תמונות ללא קטגוריות בדרך כלל אינן שימושיות. להמשיך ללא בחירת קטגוריות?</string>
@ -613,6 +613,8 @@
<string name="title_for_media">מדיה</string> <string name="title_for_media">מדיה</string>
<string name="title_for_child_classes">מחלקות יורשות</string> <string name="title_for_child_classes">מחלקות יורשות</string>
<string name="title_for_parent_classes">מחלקות מורישות</string> <string name="title_for_parent_classes">מחלקות מורישות</string>
<string name="title_for_subcategories">תת־קטגוריות</string>
<string name="title_for_parent_categories">קטגוריות הורה</string>
<string name="upload_nearby_place_found_title">נמצא מקום בסביבה</string> <string name="upload_nearby_place_found_title">נמצא מקום בסביבה</string>
<string name="upload_nearby_place_found_description_plural">האם אלו תמונות של %1$s?</string> <string name="upload_nearby_place_found_description_plural">האם אלו תמונות של %1$s?</string>
<string name="upload_nearby_place_found_description_singular">האם זאת תמונה של %1$s?</string> <string name="upload_nearby_place_found_description_singular">האם זאת תמונה של %1$s?</string>
@ -862,4 +864,5 @@
<string name="show_in_nearby">בתצוגת בסביבה</string> <string name="show_in_nearby">בתצוגת בסביבה</string>
<string name="image_tag_line_created_and_uploaded_by">נוצר והועלה על־ידי: %1$s</string> <string name="image_tag_line_created_and_uploaded_by">נוצר והועלה על־ידי: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">נוצר על־ידי %1$s והועלה על־ידי %2$s</string> <string name="image_tag_line_created_by_and_uploaded_by">נוצר על־ידי %1$s והועלה על־ידי %2$s</string>
<string name="nominated_for_deletion_btn">הועמדה למחיקה</string>
</resources> </resources>

View file

@ -408,7 +408,7 @@
<string name="deletion_reason_bad_for_my_privacy">自分のプライバシーを傷つけると気がつきました</string> <string name="deletion_reason_bad_for_my_privacy">自分のプライバシーを傷つけると気がつきました</string>
<string name="deletion_reason_no_longer_want_public">以前とは考えが変わりました。今後は公衆の場で自分の画像を公開したくありません</string> <string name="deletion_reason_no_longer_want_public">以前とは考えが変わりました。今後は公衆の場で自分の画像を公開したくありません</string>
<string name="deletion_reason_not_interesting">残念ですがこの画像は百科事典の目的に合いません</string> <string name="deletion_reason_not_interesting">残念ですがこの画像は百科事典の目的に合いません</string>
<string name="uploaded_by_myself">私本人が%1$sにアップロードし、%2$d件の記事で使用されました。</string> <string name="uploaded_by_myself" fuzzy="true">私本人が%1$sにアップロードし、%2$d件の記事で使用されました。</string>
<string name="no_uploads">コモンズへようこそ!\n\n追加ボタンを押して、ぜひご自分のメディアの初投稿をしましょう。</string> <string name="no_uploads">コモンズへようこそ!\n\n追加ボタンを押して、ぜひご自分のメディアの初投稿をしましょう。</string>
<string name="no_categories_selected">カテゴリが選択されていません</string> <string name="no_categories_selected">カテゴリが選択されていません</string>
<string name="no_categories_selected_warning_desc">カテゴリを指定しない画像は使用されることがほとんどありません。ほんとうにカテゴリを選択しないまま作業を続けますか?</string> <string name="no_categories_selected_warning_desc">カテゴリを指定しない画像は使用されることがほとんどありません。ほんとうにカテゴリを選択しないまま作業を続けますか?</string>

View file

@ -113,6 +113,7 @@
<string name="login_failed_throttled">Кёб джетишимсиз сынау болду. Тилейбиз, талай минст сора энтда кёрюгюз.</string> <string name="login_failed_throttled">Кёб джетишимсиз сынау болду. Тилейбиз, талай минст сора энтда кёрюгюз.</string>
<string name="login_failed_blocked">Кечериксиз, бу хайырланыучу Гёзенде блок этилгенди</string> <string name="login_failed_blocked">Кечериксиз, бу хайырланыучу Гёзенде блок этилгенди</string>
<string name="login_failed_2fa_needed">Эки факторлу аутентификация кодну берирге керексиз.</string> <string name="login_failed_2fa_needed">Эки факторлу аутентификация кодну берирге керексиз.</string>
<string name="login_failed_email_auth_needed">Бегитиу код электрон почта адресигизге джиберилгенди. Кирир ючюн аны салыгъыз.</string>
<string name="login_failed_generic">Системагъа кириуде халат</string> <string name="login_failed_generic">Системагъа кириуде халат</string>
<string name="share_upload_button">Джюкле</string> <string name="share_upload_button">Джюкле</string>
<string name="multiple_share_base_title">Бу къауумха ат бер</string> <string name="multiple_share_base_title">Бу къауумха ат бер</string>
@ -216,6 +217,7 @@
<string name="become_a_tester_title">Бета-Тестер болугъуз</string> <string name="become_a_tester_title">Бета-Тестер болугъуз</string>
<string name="become_a_tester_description">Google Play-де бета каналыбызгъа къошулугъуз эмда джангы функциялагъа эмда халат тюзетиулеге эртде джетишигиз</string> <string name="become_a_tester_description">Google Play-де бета каналыбызгъа къошулугъуз эмда джангы функциялагъа эмда халат тюзетиулеге эртде джетишигиз</string>
<string name="_2fa_code">2FA Код</string> <string name="_2fa_code">2FA Код</string>
<string name="email_auth_code">Электрон почтаны верификация этигиз</string>
<string name="logout_verification">Кертиден чыгъаргъа излеймисиз?</string> <string name="logout_verification">Кертиден чыгъаргъа излеймисиз?</string>
<string name="mediaimage_failed">Медиа Сурат Джетишимсизди</string> <string name="mediaimage_failed">Медиа Сурат Джетишимсизди</string>
<string name="no_subcategory_found">Тюб категория табылмады</string> <string name="no_subcategory_found">Тюб категория табылмады</string>
@ -409,7 +411,7 @@
<string name="deletion_reason_bad_for_my_privacy">Ташалыгъыма аман болгъанын ангыладым</string> <string name="deletion_reason_bad_for_my_privacy">Ташалыгъыма аман болгъанын ангыладым</string>
<string name="deletion_reason_no_longer_want_public">Сагъышымы тюрлендирдим, энди хар кимге кёрюннюгюмю излемейме</string> <string name="deletion_reason_no_longer_want_public">Сагъышымы тюрлендирдим, энди хар кимге кёрюннюгюмю излемейме</string>
<string name="deletion_reason_not_interesting">Кечериксиз, бу сурат энциклопедия ючюн эс бёлюрча тюлдю</string> <string name="deletion_reason_not_interesting">Кечериксиз, бу сурат энциклопедия ючюн эс бёлюрча тюлдю</string>
<string name="uploaded_by_myself">Кесим джюклеген %1$s сайтха джюкленди эмда %2$d статьяда хайырландырылды.</string> <string name="uploaded_by_myself">Кесим джюклеген %1$s сайтха джюкленди эмда эм азы бла %2$d статьяда хайырландырылды.</string>
<string name="no_uploads">Гёзеннге Хош Келигиз!\n\nКъош тиекге басыб биринчи медиагъызны джюклегиз.</string> <string name="no_uploads">Гёзеннге Хош Келигиз!\n\nКъош тиекге басыб биринчи медиагъызны джюклегиз.</string>
<string name="no_categories_selected">Категорияла Сайланмадыла</string> <string name="no_categories_selected">Категорияла Сайланмадыла</string>
<string name="no_categories_selected_warning_desc">Категориясыз суратла аз хайырланадыла. Категория сайламай бардырыргъа излегенигизге ишексизмисиз?</string> <string name="no_categories_selected_warning_desc">Категориясыз суратла аз хайырланадыла. Категория сайламай бардырыргъа излегенигизге ишексизмисиз?</string>
@ -779,6 +781,7 @@
<string name="talk">Сюзюу</string> <string name="talk">Сюзюу</string>
<string name="write_something_about_the_item">%1$s элементни юсюнден бир затла джазыгъыз. Буну хар ким да кёрлюкдю.</string> <string name="write_something_about_the_item">%1$s элементни юсюнден бир затла джазыгъыз. Буну хар ким да кёрлюкдю.</string>
<string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">\'%1$s\' энди бар тюлдю, аны картха алырча тюлдю.</string> <string name="does_not_exist_anymore_no_picture_can_ever_be_taken_of_it">\'%1$s\' энди бар тюлдю, аны картха алырча тюлдю.</string>
<string name="is_at_a_different_place_wikidata">\'%1$s\' башха джердеди.</string>
<string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">\'%1$s\' - башха джерди. Тилейбиз, тюз джерни энишгерекде белгилегиз, эмда мадар бар эсе, тюз кенглик бла узунлукъну джазыгъыз.</string> <string name="is_at_a_different_place_please_specify_the_correct_place_below_if_possible_tell_us_the_correct_latitude_longitude">\'%1$s\' - башха джерди. Тилейбиз, тюз джерни энишгерекде белгилегиз, эмда мадар бар эсе, тюз кенглик бла узунлукъну джазыгъыз.</string>
<string name="other_problem_or_information_please_explain_below">Башха проблема неда информация (тилейбиз, энишгерекде ангылатыгъыз).</string> <string name="other_problem_or_information_please_explain_below">Башха проблема неда информация (тилейбиз, энишгерекде ангылатыгъыз).</string>
<string name="feedback_destination_note">Сизни кери оюмугъуз тюбюндеги вики бетге джиберилликди: &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\"&gt;Commons:Mobile app/Feedback&lt;/a&gt;</string> <string name="feedback_destination_note">Сизни кери оюмугъуз тюбюндеги вики бетге джиберилликди: &lt;a href=\"https://commons.wikimedia.org/wiki/Commons:Mobile_app/Feedback\"&gt;Commons:Mobile app/Feedback&lt;/a&gt;</string>
@ -815,4 +818,7 @@
<string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Алгъышлайбыз, бу альбомна бютеу сратла не джюкленнгендиле, неда джюкленирге джораланмагъанлача белгиленнгендиле.</string> <string name="congratulations_all_pictures_in_this_album_have_been_either_uploaded_or_marked_as_not_for_upload">Алгъышлайбыз, бу альбомна бютеу сратла не джюкленнгендиле, неда джюкленирге джораланмагъанлача белгиленнгендиле.</string>
<string name="show_in_explore">Explore-де кёргюз</string> <string name="show_in_explore">Explore-де кёргюз</string>
<string name="show_in_nearby">Nearby-да кёргюз</string> <string name="show_in_nearby">Nearby-да кёргюз</string>
<string name="image_tag_line_created_and_uploaded_by">Болдургъан эм джюклеген: %1$s</string>
<string name="image_tag_line_created_by_and_uploaded_by">%1$s болдурду эмда %2$s джюкледи</string>
<string name="nominated_for_deletion_btn">Кетериуге теджелгенди</string>
</resources> </resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="crash_dialog_title">کامَنٕز گوو رُکِتھ</string>
<string name="crash_dialog_text">Oops. کیہہ تام گوو غلط!</string>
<string name="crash_dialog_comment_prompt">ؤنِیوٚ اَسہِ توٚہہِ کیاہ ٲسِیوٚ کران، تہٕ کٕریٚو تہِ اَسہِ سٕتی شیر بذریعہِ برقی خط. یُس مَدَتھ کَرِ اَسہِ اَتھ شہَرنَس منٛز!</string>
<string name="crash_dialog_ok_toast">شُکریہ!</string>
</resources>

View file

@ -345,7 +345,7 @@
<string name="deletion_reason_bad_for_my_privacy">M tɛn\'ɛs ye di na an bɛ\'ɛd tisi m mɛŋ gu\'udim yɛla</string> <string name="deletion_reason_bad_for_my_privacy">M tɛn\'ɛs ye di na an bɛ\'ɛd tisi m mɛŋ gu\'udim yɛla</string>
<string name="deletion_reason_no_longer_want_public">M tiaki m pʋtɛ\'ɛr, m pʋ lɛm bɔɔd ye di bɛ zin\'ikanɛ ka sɔ\' wʋsa na nyɛ ya\'asa</string> <string name="deletion_reason_no_longer_want_public">M tiaki m pʋtɛ\'ɛr, m pʋ lɛm bɔɔd ye di bɛ zin\'ikanɛ ka sɔ\' wʋsa na nyɛ ya\'asa</string>
<string name="deletion_reason_not_interesting">Gafara footo kaŋa pʋ nar ye di bɛ encyclopedia</string> <string name="deletion_reason_not_interesting">Gafara footo kaŋa pʋ nar ye di bɛ encyclopedia</string>
<string name="uploaded_by_myself">M kpɛ\'ɛsidinɛ %1$s m mɛŋ, ka nɔki tʋm %2$d atikil (nam) ni.</string> <string name="uploaded_by_myself" fuzzy="true">M kpɛ\'ɛsidinɛ %1$s m mɛŋ, ka nɔki tʋm %2$d atikil (nam) ni.</string>
<string name="no_uploads">Commons pʋ\'ʋsidif ken-ken!\n\nKpɛn\'ɛmi fʋ yiiga media dɔlisid fʋn na din paasim la.</string> <string name="no_uploads">Commons pʋ\'ʋsidif ken-ken!\n\nKpɛn\'ɛmi fʋ yiiga media dɔlisid fʋn na din paasim la.</string>
<string name="no_categories_selected">Fʋ pʋ gaŋ buudsi\'a</string> <string name="no_categories_selected">Fʋ pʋ gaŋ buudsi\'a</string>
<string name="no_depictions_selected">Fʋ pʋ gaŋ banɛ nwan taaba</string> <string name="no_depictions_selected">Fʋ pʋ gaŋ banɛ nwan taaba</string>

Some files were not shown because too many files have changed in this diff Show more