Compare commits

..

54 Commits

Author SHA1 Message Date
Grishka
6c1c5b7759 Merge branch 'l10n_master' 2023-10-03 03:53:50 +03:00
Grishka
1f4152b588 Fix #705 and improve handling of unknown attachment dimensions 2023-10-03 02:52:07 +03:00
Grishka
70386ea1b2 Update appkit to finally fix that ViewPager2 crash 2023-10-03 02:11:04 +03:00
Eugen Rochko
cbce90c461 New translations strings.xml (Sinhala) 2023-10-02 21:16:49 +02:00
Eugen Rochko
74ae3bf706 New translations strings.xml (Armenian) 2023-10-02 07:26:27 +02:00
Grishka
1feccdc26d Fixes 2023-10-01 23:11:33 +03:00
Eugen Rochko
c38c2a425b New translations strings.xml (Indonesian) 2023-10-01 17:30:46 +02:00
Eugen Rochko
f43352b790 New translations strings.xml (Indonesian) 2023-10-01 16:30:51 +02:00
Grishka
c5b52b2781 Fix default server not loading sometimes 2023-10-01 12:17:21 +03:00
Grishka
b91840fb95 Another attempt to fix ZoomPanView crash 2023-10-01 07:16:21 +03:00
Grishka
fc10fbffb0 Clear fragment stack instead of restarting activity
grishka/appkit#13
2023-09-30 21:53:02 +03:00
Eugen Rochko
e40841c128 New translations strings.xml (Portuguese, Brazilian) 2023-09-30 20:26:54 +02:00
Eugen Rochko
98a02e874b New translations strings.xml (Vietnamese) 2023-09-30 15:05:49 +02:00
Eugen Rochko
b06df8c3d0 New translations strings.xml (Galician) 2023-09-29 07:53:31 +02:00
Grishka
a00afd5d7f Same crash fix in 2 more places ugh 2023-09-29 03:20:58 +03:00
Grishka
9a41a2d6fb Merge branch 'l10n_master' 2023-09-28 20:14:21 +03:00
Grishka
2cd98a6620 More crash fixes 2023-09-28 20:11:43 +03:00
Grishka
283b56be5b Finally fix the mysterious RecyclerView crash 2023-09-28 19:56:25 +03:00
Eugen Rochko
6d56771aba New translations strings.xml (Galician) 2023-09-28 16:51:59 +02:00
Grishka
1724d8a532 Probably fix #703 2023-09-27 19:50:59 +03:00
Eugen Rochko
b4cdf35d36 New translations strings.xml (Russian) 2023-09-25 23:39:42 +02:00
Eugen Rochko
cad0ad7a59 New translations strings.xml (Ukrainian) 2023-09-25 22:25:17 +02:00
Grishka
ca60003c39 Fix #682 2023-09-25 23:11:10 +03:00
Grishka
0f030e0bac Fix #683 2023-09-25 23:07:34 +03:00
Grishka
6d4f212a18 Probably need to set this too 2023-09-25 23:00:15 +03:00
Grishka
183b39bc24 Specify LED color for notifications
closes #695
2023-09-25 22:58:08 +03:00
Grishka
27ad0c6fcf Crash fixes 2023-09-25 22:52:51 +03:00
Grishka
b5f661f1af I forgot to increment the version code 2023-09-25 19:25:59 +03:00
Grishka
0015f3f0bf Merge branch 'l10n_master' 2023-09-25 19:22:38 +03:00
Eugen Rochko
c5d0fdd645 New translations strings.xml (Turkish) 2023-09-25 18:20:56 +02:00
Grishka
2d09ad44fb Merge branch 'l10n_master' 2023-09-25 19:18:24 +03:00
Eugen Rochko
667fffd124 New translations strings.xml (Chinese Traditional) 2023-09-25 18:18:22 +02:00
Eugen Rochko
699233d8c7 New translations strings.xml (Filipino) 2023-09-25 18:18:05 +02:00
Grishka
56aabdc4a6 Fix empty view text style
closes #701
2023-09-25 19:12:04 +03:00
Grishka
443e2c7a6f Add a tool to detect invalid formatting in localized strings 2023-09-25 18:51:49 +03:00
Eugen Rochko
985b0f6e63 New translations strings.xml (Filipino) 2023-09-25 17:49:57 +02:00
Grishka
cc86edf276 Fix #700 2023-09-25 17:18:42 +03:00
Grishka
4071b9342d Update appkit 2023-09-25 17:13:59 +03:00
Eugen Rochko
f71d1bc5d3 New translations strings.xml (Greek) 2023-09-24 23:27:13 +02:00
Eugen Rochko
6bcdbaba34 New translations strings.xml (Turkish) 2023-09-24 08:49:38 +02:00
Eugen Rochko
a2beead3a5 New translations strings.xml (Chinese Simplified) 2023-09-23 18:34:38 +02:00
Eugen Rochko
e7a25e353d New translations strings.xml (Japanese) 2023-09-23 14:15:37 +02:00
Eugen Rochko
af04a01130 New translations strings.xml (Japanese) 2023-09-23 13:16:04 +02:00
Grishka
fe1cfa1d7b Fix indexable setting 2023-09-22 21:33:21 +03:00
Eugen Rochko
b248797bb0 New translations strings.xml (Russian) 2023-09-22 20:28:14 +02:00
Grishka
f24eba08d3 Fix custom emojis in names setting 2023-09-22 21:27:30 +03:00
Eugen Rochko
0e89559a47 New translations strings.xml (Slovenian) 2023-09-22 19:30:53 +02:00
Eugen Rochko
d02a72e079 New translations strings.xml (Japanese) 2023-09-22 13:01:51 +02:00
Eugen Rochko
3be57d1b0b New translations strings.xml (Japanese) 2023-09-22 11:08:13 +02:00
Eugen Rochko
bed550e97c New translations strings.xml (Russian) 2023-09-22 09:19:11 +02:00
Eugen Rochko
7e2619ea75 New translations strings.xml (Italian) 2023-09-22 01:48:10 +02:00
Eugen Rochko
4b22f1d3a7 New translations strings.xml (Thai) 2023-09-21 21:39:59 +02:00
Eugen Rochko
9dcc7e293f New translations strings.xml (Icelandic) 2023-09-21 15:39:27 +02:00
Eugen Rochko
6a68cf5e41 New translations strings.xml (Persian) 2023-09-21 13:13:31 +02:00
50 changed files with 740 additions and 99 deletions

View File

@@ -9,8 +9,8 @@ android {
applicationId "org.joinmastodon.android"
minSdk 23
targetSdk 33
versionCode 66
versionName "2.1.0"
versionCode 72
versionName "2.1.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "da-rDK", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fa-rIR", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "ig-rNG", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "my-rMM", "nl-rNL", "no-rNO", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "ur-rIN", "vi-rVN", "zh-rCN", "zh-rTW"
}
@@ -76,7 +76,7 @@ dependencies {
implementation 'me.grishka.litex:viewpager:1.0.0'
implementation 'me.grishka.litex:viewpager2:1.0.0'
implementation 'me.grishka.litex:palette:1.0.0'
implementation 'me.grishka.appkit:appkit:1.2.9'
implementation 'me.grishka.appkit:appkit:1.2.14'
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'org.jsoup:jsoup:1.14.3'
implementation 'com.squareup:otto:1.3.8'

View File

@@ -42,40 +42,7 @@ public class MainActivity extends FragmentStackActivity{
super.onCreate(savedInstanceState);
if(savedInstanceState==null){
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
showFragmentClearingBackStack(new SplashFragment());
}else{
AccountSessionManager.getInstance().maybeUpdateLocalInfo();
AccountSession session;
Bundle args=new Bundle();
Intent intent=getIntent();
if(intent.getBooleanExtra("fromNotification", false)){
String accountID=intent.getStringExtra("accountID");
try{
session=AccountSessionManager.getInstance().getAccount(accountID);
if(!intent.hasExtra("notification"))
args.putString("tab", "notifications");
}catch(IllegalStateException x){
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
}else{
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
args.putString("account", session.getID());
Fragment fragment=session.activated ? new HomeFragment() : new AccountActivationFragment();
fragment.setArguments(args);
showFragmentClearingBackStack(fragment);
if(intent.getBooleanExtra("fromNotification", false) && intent.hasExtra("notification")){
Notification notification=Parcels.unwrap(intent.getParcelableExtra("notification"));
showFragmentForNotification(notification, session.getID());
}else if(intent.getBooleanExtra("compose", false)){
showCompose();
}else if(Intent.ACTION_VIEW.equals(intent.getAction())){
handleURL(intent.getData(), null);
}else{
maybeRequestNotificationsPermission();
}
}
restartHomeFragment();
}
if(BuildConfig.BUILD_TYPE.startsWith("appcenter")){
@@ -200,4 +167,41 @@ public class MainActivity extends FragmentStackActivity{
requestPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS}, 100);
}
}
public void restartHomeFragment(){
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
showFragmentClearingBackStack(new SplashFragment());
}else{
AccountSessionManager.getInstance().maybeUpdateLocalInfo();
AccountSession session;
Bundle args=new Bundle();
Intent intent=getIntent();
if(intent.getBooleanExtra("fromNotification", false)){
String accountID=intent.getStringExtra("accountID");
try{
session=AccountSessionManager.getInstance().getAccount(accountID);
if(!intent.hasExtra("notification"))
args.putString("tab", "notifications");
}catch(IllegalStateException x){
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
}else{
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
args.putString("account", session.getID());
Fragment fragment=session.activated ? new HomeFragment() : new AccountActivationFragment();
fragment.setArguments(args);
showFragmentClearingBackStack(fragment);
if(intent.getBooleanExtra("fromNotification", false) && intent.hasExtra("notification")){
Notification notification=Parcels.unwrap(intent.getParcelableExtra("notification"));
showFragmentForNotification(notification, session.getID());
}else if(intent.getBooleanExtra("compose", false)){
showCompose();
}else if(Intent.ACTION_VIEW.equals(intent.getAction())){
handleURL(intent.getData(), null);
}else{
maybeRequestNotificationsPermission();
}
}
}
}

View File

@@ -118,6 +118,8 @@ public class PushNotificationReceiver extends BroadcastReceiver{
List<NotificationChannel> channels=Arrays.stream(PushNotification.Type.values())
.map(type->{
NotificationChannel channel=new NotificationChannel(accountID+"_"+type, context.getString(type.localizedName), NotificationManager.IMPORTANCE_DEFAULT);
channel.setLightColor(context.getColor(R.color.primary_700));
channel.enableLights(true);
channel.setGroup(accountID);
return channel;
})
@@ -147,6 +149,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
.setShowWhen(true)
.setCategory(Notification.CATEGORY_SOCIAL)
.setAutoCancel(true)
.setLights(context.getColor(R.color.primary_700), 500, 1000)
.setColor(context.getColor(R.color.primary_700));
if(avatar!=null){
builder.setLargeIcon(UiUtils.getBitmapFromDrawable(avatar));

View File

@@ -195,7 +195,7 @@ public class AccountSession{
public void savePreferencesIfPending(){
if(preferencesNeedSaving){
new UpdateAccountCredentialsPreferences(preferences, null, self.discoverable, !self.noindex)
new UpdateAccountCredentialsPreferences(preferences, null, self.discoverable, self.source.indexable)
.setCallback(new Callback<>(){
@Override
public void onSuccess(Account result){

View File

@@ -176,7 +176,7 @@ public class HashtagTimelineFragment extends StatusListFragment{
}
private void updateHeader(){
if(hashtag==null)
if(hashtag==null || getActivity()==null)
return;
if(hashtag.history!=null && !hashtag.history.isEmpty()){

View File

@@ -150,6 +150,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
});
}
}
tabBar.selectTab(currentTab);
return content;
}

View File

@@ -1044,9 +1044,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
@NonNull
@Override
public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
FrameLayout view=tabViews[viewType];
((ViewGroup)view.getParent()).removeView(view);
view.setVisibility(View.VISIBLE);
FrameLayout view=new FrameLayout(parent.getContext());
view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return new SimpleViewHolder(view);
}
@@ -1054,8 +1052,13 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
@Override
public void onBindViewHolder(@NonNull SimpleViewHolder holder, int position){
Fragment fragment=getFragmentForPage(position);
FrameLayout fragmentView=tabViews[position];
fragmentView.setVisibility(View.VISIBLE);
if(fragmentView.getParent() instanceof ViewGroup parent)
parent.removeView(fragmentView);
((FrameLayout)holder.itemView).addView(fragmentView);
if(!fragment.isAdded()){
getChildFragmentManager().beginTransaction().add(holder.itemView.getId(), fragment).commit();
getChildFragmentManager().beginTransaction().add(fragmentView.getId(), fragment).commit();
holder.itemView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
@Override
public boolean onPreDraw(){

View File

@@ -47,13 +47,12 @@ public class SplashFragment extends AppKitFragment{
private ProgressBarButton defaultServerButton;
private ProgressBar defaultServerProgress;
private String chosenDefaultServer=DEFAULT_SERVER;
private boolean loadingDefaultServer;
private boolean loadingDefaultServer, loadedDefaultServer;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
motionEffect=new InterpolatingMotionEffect(MastodonApp.context);
loadAndChooseDefaultServer();
}
@Nullable
@@ -101,6 +100,8 @@ public class SplashFragment extends AppKitFragment{
});
}
});
if(!loadedDefaultServer && !loadingDefaultServer)
loadAndChooseDefaultServer();
return contentView;
}
@@ -239,6 +240,7 @@ public class SplashFragment extends AppKitFragment{
private void setChosenDefaultServer(String domain){
chosenDefaultServer=domain;
loadingDefaultServer=false;
loadedDefaultServer=true;
if(defaultServerButton!=null && getActivity()!=null){
defaultServerButton.setTextVisible(true);
defaultServerProgress.setVisibility(View.GONE);

View File

@@ -17,6 +17,7 @@ import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusContext;
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.SpoilerStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
import org.joinmastodon.android.ui.text.HtmlParser;
@@ -61,6 +62,12 @@ public class ThreadFragment extends StatusListFragment{
text.textSelectable=true;
else if(item instanceof FooterStatusDisplayItem footer)
footer.hideCounts=true;
else if(item instanceof SpoilerStatusDisplayItem spoiler){
for(StatusDisplayItem subItem:spoiler.contentItems){
if(subItem instanceof TextStatusDisplayItem text)
text.textSelectable=true;
}
}
}
items.add(new ExtendedFooterStatusDisplayItem(s.id, this, s.getContentStatus()));
}

View File

@@ -280,15 +280,19 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
@NonNull
@Override
public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
FrameLayout view=tabViews[viewType];
((ViewGroup)view.getParent()).removeView(view);
view.setVisibility(View.VISIBLE);
FrameLayout view=new FrameLayout(parent.getContext());
view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return new SimpleViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull SimpleViewHolder holder, int position){}
public void onBindViewHolder(@NonNull SimpleViewHolder holder, int position){
FrameLayout view=tabViews[position];
if(view.getParent() instanceof ViewGroup parent)
parent.removeView(view);
view.setVisibility(View.VISIBLE);
((FrameLayout)holder.itemView).addView(view, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
@Override
public int getItemCount(){

View File

@@ -384,6 +384,8 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
}
private void onSearchViewEnter(){
if(TextUtils.isEmpty(currentQuery) || currentQuery.trim().isEmpty())
return;
deliverResult(currentQuery, null);
}

View File

@@ -165,9 +165,7 @@ public class AccountActivationFragment extends ToolbarFragment{
private void tryGetAccount(){
if(AccountSessionManager.getInstance().tryGetAccount(accountID)==null){
uiHandler.removeCallbacks(pollRunnable);
getActivity().finish();
Intent intent=new Intent(getActivity(), MainActivity.class);
startActivity(intent);
((MainActivity)getActivity()).restartHomeFragment();
return;
}
currentRequest=new GetOwnAccount()

View File

@@ -156,9 +156,7 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
.setMessage(getString(R.string.confirm_log_out, session.getFullUsername()))
.setPositiveButton(R.string.log_out, (dialog, which)->AccountSessionManager.get(accountID).logOut(getActivity(), ()->{
loggedOut=true;
getActivity().finish();
Intent intent=new Intent(getActivity(), MainActivity.class);
startActivity(intent);
((MainActivity)getActivity()).restartHomeFragment();
}))
.setNegativeButton(R.string.cancel, null)
.show();

View File

@@ -19,8 +19,10 @@ public class SettingsPrivacyFragment extends BaseSettingsFragment<Void>{
Account self=AccountSessionManager.get(accountID).self;
onDataLoaded(List.of(
discoverableItem=new CheckableListItem<>(R.string.settings_discoverable, 0, CheckableListItem.Style.SWITCH, self.discoverable, R.drawable.ic_thumbs_up_down_24px, ()->toggleCheckableItem(discoverableItem)),
indexableItem=new CheckableListItem<>(R.string.settings_indexable, 0, CheckableListItem.Style.SWITCH, self.indexable, R.drawable.ic_search_24px, ()->toggleCheckableItem(indexableItem))
indexableItem=new CheckableListItem<>(R.string.settings_indexable, 0, CheckableListItem.Style.SWITCH, self.source.indexable!=null ? self.source.indexable : true, R.drawable.ic_search_24px, ()->toggleCheckableItem(indexableItem))
));
if(self.source.indexable==null)
indexableItem.isEnabled=false;
}
@Override
@@ -30,9 +32,9 @@ public class SettingsPrivacyFragment extends BaseSettingsFragment<Void>{
public void onPause(){
super.onPause();
Account self=AccountSessionManager.get(accountID).self;
if(self.discoverable!=discoverableItem.checked || self.indexable!=indexableItem.checked){
if(self.discoverable!=discoverableItem.checked || (self.source.indexable!=null && self.source.indexable!=indexableItem.checked)){
self.discoverable=discoverableItem.checked;
self.indexable=indexableItem.checked;
self.source.indexable=indexableItem.checked;
AccountSessionManager.get(accountID).savePreferencesLater();
}
}

View File

@@ -146,18 +146,21 @@ public class SettingsServerFragment extends AppKitFragment{
@NonNull
@Override
public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
FrameLayout view=tabViews[viewType];
((ViewGroup)view.getParent()).removeView(view);
view.setVisibility(View.VISIBLE);
FrameLayout view=new FrameLayout(parent.getContext());
view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return new SimpleViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull SimpleViewHolder holder, int position){
FrameLayout view=tabViews[position];
if(view.getParent() instanceof ViewGroup parent)
parent.removeView(view);
view.setVisibility(View.VISIBLE);
((FrameLayout)holder.itemView).addView(view, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
Fragment fragment=getFragmentForPage(position);
if(!fragment.isAdded()){
getChildFragmentManager().beginTransaction().add(holder.itemView.getId(), fragment).commit();
getChildFragmentManager().beginTransaction().add(view.getId(), fragment).commit();
holder.itemView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
@Override
public boolean onPreDraw(){

View File

@@ -133,8 +133,6 @@ public class Account extends BaseModel{
*/
public Instant muteExpiresAt;
public boolean noindex;
public boolean indexable;
public boolean hideCollections;
@Override
@@ -195,8 +193,6 @@ public class Account extends BaseModel{
", suspended="+suspended+
", muteExpiresAt="+muteExpiresAt+
", noindex="+noindex+
", indexable="+indexable+
", hideCollections="+hideCollections+
'}';
}
}

View File

@@ -45,26 +45,34 @@ public class Attachment extends BaseModel{
public int getWidth(){
if(meta==null)
return 0;
return 1920;
if(meta.width>0)
return meta.width;
if(meta.original!=null && meta.original.width>0)
return meta.original.width;
if(meta.small!=null && meta.small.width>0)
return meta.small.width;
return 0;
return 1920;
}
public int getHeight(){
if(meta==null)
return 0;
return 1080;
if(meta.height>0)
return meta.height;
if(meta.original!=null && meta.original.height>0)
return meta.original.height;
if(meta.small!=null && meta.small.height>0)
return meta.small.height;
return 0;
return 1080;
}
public boolean hasKnownDimensions(){
return meta!=null && (
(meta.height>0 && meta.width>0)
|| (meta.original!=null && meta.original.height>0 && meta.original.width>0)
|| (meta.small!=null && meta.small.height>0 && meta.small.width>0)
);
}
public double getDuration(){

View File

@@ -30,4 +30,19 @@ public class Hashtag extends BaseModel implements DisplayItemsParent{
public String getID(){
return name;
}
@Override
public boolean equals(Object o){
if(this==o) return true;
if(o==null || getClass()!=o.getClass()) return false;
Hashtag hashtag=(Hashtag) o;
return name.equals(hashtag.name);
}
@Override
public int hashCode(){
return name.hashCode();
}
}

View File

@@ -20,4 +20,22 @@ public class Mention extends BaseModel{
", url='"+url+'\''+
'}';
}
@Override
public boolean equals(Object o){
if(this==o) return true;
if(o==null || getClass()!=o.getClass()) return false;
Mention mention=(Mention) o;
if(!id.equals(mention.id)) return false;
return url.equals(mention.url);
}
@Override
public int hashCode(){
int result=id.hashCode();
result=31*result+url.hashCode();
return result;
}
}

View File

@@ -37,6 +37,8 @@ public class Source extends BaseModel{
* The number of pending follow requests.
*/
public int followRequestCount;
public Boolean indexable;
public boolean hideCollections;
@Override
public void postprocess() throws ObjectValidationException{
@@ -54,6 +56,8 @@ public class Source extends BaseModel{
", sensitive="+sensitive+
", language='"+language+'\''+
", followRequestCount="+followRequestCount+
", indexable="+indexable+
", hideCollections="+hideCollections+
'}';
}
}

View File

@@ -8,6 +8,7 @@ import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
@@ -36,6 +37,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.recyclerview.widget.LinearLayoutManager;
import me.grishka.appkit.FragmentStackActivity;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
@@ -113,9 +115,7 @@ public class AccountSwitcherSheet extends BottomSheet{
private void logOut(String accountID){
AccountSessionManager.get(accountID).logOut(activity, ()->{
dismiss();
activity.finish();
Intent intent=new Intent(activity, MainActivity.class);
activity.startActivity(intent);
((MainActivity)activity).restartHomeFragment();
});
}
@@ -248,17 +248,17 @@ public class AccountSwitcherSheet extends BottomSheet{
@Override
public void onClick(){
dismiss();
if(AccountSessionManager.getInstance().getLastActiveAccountID().equals(item.getID())){
dismiss();
if(fragment!=null){
fragment.setCurrentTab(R.id.tab_profile);
}
return;
}
if(AccountSessionManager.getInstance().tryGetAccount(item.getID())!=null)
if(AccountSessionManager.getInstance().tryGetAccount(item.getID())!=null){
AccountSessionManager.getInstance().setLastActiveAccountID(item.getID());
activity.finish();
activity.startActivity(new Intent(activity, MainActivity.class));
((MainActivity)activity).restartHomeFragment();
}
}
@Override

View File

@@ -8,6 +8,7 @@ import android.view.ViewGroup;
import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.ui.text.HtmlParser;
@@ -29,7 +30,8 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon){
super(parentID, parentFragment);
SpannableStringBuilder ssb=new SpannableStringBuilder(text);
HtmlParser.parseCustomEmoji(ssb, emojis);
if(AccountSessionManager.get(parentFragment.getAccountID()).getLocalPreferences().customEmojiInNames)
HtmlParser.parseCustomEmoji(ssb, emojis);
this.text=ssb;
emojiHelper.setText(ssb);
this.icon=icon;

View File

@@ -66,6 +66,10 @@ public class BlurhashCrossfadeDrawable extends Drawable{
public void setImageDrawable(Drawable imageDrawable){
this.imageDrawable=imageDrawable;
if(imageDrawable!=null){
width=imageDrawable.getIntrinsicWidth();
height=imageDrawable.getIntrinsicHeight();
}
invalidateSelf();
}

View File

@@ -716,9 +716,18 @@ public class PhotoViewer implements ZoomPanView.Listener{
public void onBind(Attachment item){
super.onBind(item);
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) imageView.getLayoutParams();
params.width=item.getWidth();
params.height=item.getHeight();
ViewImageLoader.load(this, listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition()), new UrlImageLoaderRequest(item.url), false);
Drawable currentDrawable=listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition());
if(item.hasKnownDimensions()){
params.width=item.getWidth();
params.height=item.getHeight();
}else if(currentDrawable!=null){
params.width=currentDrawable.getIntrinsicWidth();
params.height=currentDrawable.getIntrinsicHeight();
}else{
params.width=1920;
params.height=1080;
}
ViewImageLoader.load(this, currentDrawable, new UrlImageLoaderRequest(item.url), false);
}
@Override
@@ -760,9 +769,18 @@ public class PhotoViewer implements ZoomPanView.Listener{
super.onBind(item);
playerReady=false;
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) wrap.getLayoutParams();
params.width=item.getWidth();
params.height=item.getHeight();
wrap.setBackground(listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition()));
Drawable currentDrawable=listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition());
if(item.hasKnownDimensions()){
params.width=item.getWidth();
params.height=item.getHeight();
}else if(currentDrawable!=null){
params.width=currentDrawable.getIntrinsicWidth();
params.height=currentDrawable.getIntrinsicHeight();
}else{
params.width=1920;
params.height=1080;
}
wrap.setBackground(currentDrawable);
progressBar.setVisibility(item.type==Attachment.Type.VIDEO ? View.VISIBLE : View.GONE);
if(itemView.isAttachedToWindow()){
reset();
@@ -822,7 +840,9 @@ public class PhotoViewer implements ZoomPanView.Listener{
@Override
public boolean onError(MediaPlayer mp, int what, int extra){
Log.e(TAG, "video player onError() called with: mp = ["+mp+"], what = ["+what+"], extra = ["+extra+"]");
return false;
Toast.makeText(activity, R.string.error_playing_video, Toast.LENGTH_SHORT).show();
onStartSwipeToDismissTransition(0f);
return true;
}
public void prepareAndStartPlayer(){
@@ -843,6 +863,8 @@ public class PhotoViewer implements ZoomPanView.Listener{
player.prepareAsync();
}catch(IOException x){
Log.w(TAG, "Error initializing gif player", x);
Toast.makeText(activity, R.string.error_playing_video, Toast.LENGTH_SHORT).show();
onStartSwipeToDismissTransition(0f);
}
}

View File

@@ -119,6 +119,11 @@ public class ZoomPanView extends FrameLayout implements ScaleGestureDetector.OnS
int width=right-left;
int height=bottom-top;
if(width==0 || height==0 || child.getWidth()==0 || child.getWidth()==0){
matrix.reset();
return;
}
float scale=Math.min(width/(float)child.getWidth(), height/(float)child.getHeight());
minScale=scale;
maxScale=Math.max(3f, height/(float)child.getHeight());
@@ -306,8 +311,6 @@ public class ZoomPanView extends FrameLayout implements ScaleGestureDetector.OnS
}, 1f).setMinimumVisibleChange(DynamicAnimation.MIN_VISIBLE_CHANGE_ALPHA));
}
}else{
if(animatingTransition)
Log.w(TAG, "updateViewTransform: ", new Throwable().fillInStackTrace());
child.setScaleX(matrixValues[Matrix.MSCALE_X]);
child.setScaleY(matrixValues[Matrix.MSCALE_Y]);
child.setTranslationX(matrixValues[Matrix.MTRANS_X]);

View File

@@ -81,10 +81,10 @@ public class HtmlParser{
}
}
Map<String, String> idsByUrl=mentions.stream().collect(Collectors.toMap(m->m.url, m->m.id));
Map<String, String> idsByUrl=mentions.stream().distinct().collect(Collectors.toMap(m->m.url, m->m.id));
// Hashtags in remote posts have remote URLs, these have local URLs so they don't match.
// Map<String, String> tagsByUrl=tags.stream().collect(Collectors.toMap(t->t.url, t->t.name));
Map<String, Hashtag> tagsByTag=tags.stream().collect(Collectors.toMap(t->t.name.toLowerCase(), Function.identity()));
Map<String, Hashtag> tagsByTag=tags.stream().distinct().collect(Collectors.toMap(t->t.name.toLowerCase(), Function.identity()));
final SpannableStringBuilder ssb=new SpannableStringBuilder();
Jsoup.parseBodyFragment(source).body().traverse(new NodeVisitor(){

View File

@@ -27,6 +27,7 @@ public class MediaAttachmentViewController{
private final Context context;
private boolean didClear;
private Status status;
private Attachment attachment;
public MediaAttachmentViewController(Context context, MediaGridStatusDisplayItem.GridItemType type){
view=context.getSystemService(LayoutInflater.class).inflate(switch(type){
@@ -50,6 +51,7 @@ public class MediaAttachmentViewController{
public void bind(Attachment attachment, Status status){
this.status=status;
this.attachment=attachment;
crossfadeDrawable.setSize(attachment.getWidth(), attachment.getHeight());
crossfadeDrawable.setBlurhashDrawable(attachment.blurhashPlaceholder);
crossfadeDrawable.setCrossfadeAlpha(0f);
@@ -69,6 +71,11 @@ public class MediaAttachmentViewController{
crossfadeDrawable.setImageDrawable(drawable);
if(didClear)
crossfadeDrawable.animateAlpha(0f);
// Make sure the image is not stretched if the server returned wrong dimensions
if(drawable!=null && (drawable.getIntrinsicWidth()!=attachment.getWidth() || drawable.getIntrinsicHeight()!=attachment.getHeight())){
photo.setImageDrawable(null);
photo.setImageDrawable(crossfadeDrawable);
}
}
public void clearImage(){

View File

@@ -2,14 +2,11 @@ package org.joinmastodon.android.ui.views;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import org.joinmastodon.android.ui.PhotoLayoutHelper;
import java.util.Arrays;
import me.grishka.appkit.utils.V;
public class MediaGridLayout extends ViewGroup{
@@ -18,7 +15,7 @@ public class MediaGridLayout extends ViewGroup{
public static final int MAX_WIDTH=400; // dp
private static final int GAP=2; // dp
private PhotoLayoutHelper.TiledLayoutResult tiledLayout;
private int[] columnStarts=new int[10], columnEnds=new int[10], rowStarts=new int[10], rowEnds=new int[10];
private int[] columnStarts, columnEnds, rowStarts, rowEnds;
public MediaGridLayout(Context context){
this(context, null);
@@ -45,6 +42,14 @@ public class MediaGridLayout extends ViewGroup{
width=Math.round(width*(tiledLayout.width/(float)PhotoLayoutHelper.MAX_WIDTH));
}
if(rowStarts==null || rowStarts.length<tiledLayout.rowSizes.length){
rowStarts=new int[tiledLayout.rowSizes.length];
rowEnds=new int[tiledLayout.rowSizes.length];
}
if(columnStarts==null || columnStarts.length<tiledLayout.columnSizes.length){
columnStarts=new int[tiledLayout.columnSizes.length];
columnEnds=new int[tiledLayout.columnSizes.length];
}
int offset=0;
for(int i=0;i<tiledLayout.columnSizes.length;i++){
columnStarts[i]=offset;
@@ -77,7 +82,7 @@ public class MediaGridLayout extends ViewGroup{
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b){
if(tiledLayout==null)
if(tiledLayout==null || rowStarts==null)
return;
int maxWidth=V.dp(MAX_WIDTH);

View File

@@ -387,6 +387,7 @@
<string name="welcome_to_mastodon">Καλώς ήρθες στο Mastodon</string>
<string name="welcome_paragraph1">Το Mastodon είναι ένα αποκεντρωμένο κοινωνικό δίκτυο που σημαίνει ότι καμία εταιρεία δεν το ελέγχει. Αποτελείται από πολλούς ανεξάρτητους διακομιστές, όλοι συνδεδεμένοι μαζί.</string>
<string name="what_are_servers">Τι είναι οι διακομιστές;</string>
<string name="welcome_paragraph2">Κάθε λογαριασμός Mastodon φιλοξενείται σε ένα διακομιστή - ο καθένας με τις δικές του αξίες, κανόνες &amp; διαχειριστές. Ανεξάρτητα από το ποιον μπορεί να επιλέξεις, μπορείς να ακολουθήσεις και να αλληλεπιδράσεις με άτομα από οποιονδήποτε διακομιστή.</string>
<string name="opening_link">Άνοιγμα συνδέσμου…</string>
<string name="link_not_supported">Αυτός ο σύνδεσμος δεν υποστηρίζεται στην εφαρμογή</string>
<string name="log_out_all_accounts">Αποσύνδεση από όλους τους λογαριασμούς</string>
@@ -582,5 +583,20 @@
<string name="time_hours_ago_short">%dώ πριν</string>
<string name="time_days_ago_short">%dημ πριν</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Μετάφραση από %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Μεταφράστηκε από %1$s χρησιμοποιώντας %2$s</string>
<string name="translation_show_original">Εμφάνιση αρχικού</string>
<string name="translation_failed">Η μετάφραση απέτυχε. Ίσως ο διαχειριστής δεν έχει ενεργοποιήσει μεταφράσεις σε αυτόν τον διακομιστή ή αυτός ο διακομιστής εκτελεί μια παλαιότερη έκδοση του Mastodon όπου οι μεταφράσεις δεν υποστηρίζονται ακόμα.</string>
<string name="settings_privacy">Ιδιωτικότητα και προσιτότητα</string>
<string name="settings_discoverable">Παροχή προφίλ και δημοσιεύσεων σε αλγορίθμους ανακάλυψης</string>
<string name="settings_indexable">Συμπερίληψη δημόσιων αναρτήσεων στα αποτελέσματα αναζήτησης</string>
<plurals name="x_participants">
<item quantity="one">%,d συμμετέχων</item>
<item quantity="other">%,d συμμετέχοντες</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="one">%,d ανάρτηση σήμερα</item>
<item quantity="other">%,d αναρτήσεις σήμερα</item>
</plurals>
</resources>

View File

@@ -588,6 +588,9 @@
<string name="post_translated">ترجمه از %1$s با %2$s</string>
<string name="translation_show_original">نمایش اصلی</string>
<string name="translation_failed">ترجمه ناموفق بود. شاید مدیر ترجمه‌ها را در این کارساز فعال نکرده باشد یا این کارساز نسخه قدیمی ماستودون را اجرا می کند که در آن ترجمه‌ها هنوز پشتیبانی نمی شوند.</string>
<string name="settings_privacy">محرمانگی و دسترسی</string>
<string name="settings_discoverable">مشخص کردن مشخصات و فرسته‌ها در الگوریتم‌های اکتشاف</string>
<string name="settings_indexable">قرار دادن فرسته‌های عمومی در نتایج جستجو</string>
<plurals name="x_participants">
<item quantity="one">%,d شرکت کننده</item>
<item quantity="other">%,d شرکت‌کننده</item>

View File

@@ -211,12 +211,12 @@
<item quantity="other">%,d tagasunod</item>
</plurals>
<plurals name="x_following">
<item quantity="one">%, d Sumusunod</item>
<item quantity="other">%, d Sumusunod</item>
<item quantity="one">%,d Sumusunod</item>
<item quantity="other">%,d Sumusunod</item>
</plurals>
<plurals name="x_favorites">
<item quantity="one">%, d Paborito</item>
<item quantity="other">%, d paborito</item>
<item quantity="one">%,d Paborito</item>
<item quantity="other">%,d paborito</item>
</plurals>
<string name="timestamp_via_app">%1$s sa pamamagitan ng %2$s</string>
<string name="time_now">ngayon</string>

View File

@@ -4,12 +4,18 @@
<string name="next">Seguinte</string>
<string name="loading_instance">Obtendo info do servidor…</string>
<string name="error">Erro</string>
<string name="not_a_mastodon_instance">%s non semella ser un servidor Mastodon.</string>
<string name="ok">OK</string>
<string name="preparing_auth">Preparándose para a autenticación…</string>
<string name="finishing_auth">Rematando coa autenticación…</string>
<string name="user_boosted">%s promoveu</string>
<string name="in_reply_to">Como resposta a %s</string>
<string name="notifications">Notificacións</string>
<string name="user_followed_you">%s comezou a seguirte</string>
<string name="user_sent_follow_request">%s enviouche unha solicitude de seguimento</string>
<string name="user_favorited">%s marcou como favorita a túa publicación</string>
<string name="notification_boosted">%s promoveu a túa publicación</string>
<string name="poll_ended">Mira os resultados dunha enquisa na que votaches</string>
<string name="share_toot_title">Compartir</string>
<string name="settings">Axustes</string>
<string name="publish">Publicar</string>
@@ -31,6 +37,7 @@
<string name="button_follow">Seguir</string>
<string name="button_following">Seguindo</string>
<string name="edit_profile">Editar perfil</string>
<string name="share_user">Compartir perfil</string>
<string name="mute_user">Acalar a %s</string>
<string name="unmute_user">Deixar de acalar a @%s</string>
<string name="block_user">Bloquear a %s</string>
@@ -78,6 +85,10 @@
<item quantity="one">Queda %d día</item>
<item quantity="other">Quedan %d días</item>
</plurals>
<plurals name="x_votes">
<item quantity="one">%,d voto</item>
<item quantity="other">%,d votos</item>
</plurals>
<string name="poll_closed">Pechada</string>
<string name="confirm_mute_title">Acalar conta</string>
<string name="confirm_mute">Confirma Acalar a %s</string>
@@ -96,27 +107,35 @@
<string name="button_blocked">Bloqueado</string>
<string name="action_vote">Votar</string>
<string name="delete">Eliminar</string>
<string name="confirm_delete_title">Eliminar publicación</string>
<string name="confirm_delete">Tes a certeza de querer eliminar esta publicación?</string>
<string name="deleting">Eliminando…</string>
<string name="notification_channel_audio_player">Reproducir música</string>
<string name="play">Reproducir</string>
<string name="pause">Deter</string>
<string name="log_out">Pechar sesión</string>
<string name="add_account">Engadir conta</string>
<string name="search_hint">Procurar</string>
<string name="hashtags">Cancelos</string>
<string name="news">Novas</string>
<string name="for_you">Para ti</string>
<string name="all_notifications">Todo</string>
<string name="mentions">Mencións</string>
<plurals name="x_people_talking">
<item quantity="one">%d persoa está comentando</item>
<item quantity="other">%d persoas están comentando</item>
</plurals>
<string name="report_title">Denunciar a %s</string>
<string name="report_choose_reason">Cal é o problema con esta publicación?</string>
<string name="report_choose_reason_account">Cal é o problema con %s?</string>
<string name="report_choose_reason_subtitle">Elixe a mellor coincidencia</string>
<string name="report_reason_personal">Non me gusta</string>
<string name="report_reason_personal_subtitle">Non é algo que queiras ver</string>
<string name="report_reason_spam">É spam</string>
<string name="report_reason_spam_subtitle">Ligazóns perigosas, relacións falsas, ou respostas repetitivas</string>
<string name="report_reason_violation">Viola as regras do servidor</string>
<string name="report_reason_violation_subtitle">Descubriches que quebra certas regras en concreto</string>
<string name="report_reason_other">É outra cousa</string>
<string name="report_reason_other_subtitle">O problema non entra noutras categorías</string>
<string name="report_choose_rule">Que regras foron incumpridas?</string>
<string name="report_choose_rule_subtitle">Elixe todo o que sexa de aplicación</string>
@@ -125,8 +144,14 @@
<string name="report_comment_title">Hai algo máis que creas debamos saber?</string>
<string name="report_comment_hint">Comentarios adicionais</string>
<string name="sending_report">Enviando a denuncia…</string>
<string name="report_sent_title">Grazas pola denuncia, investigarémola.</string>
<string name="report_sent_subtitle">Mentras revisamos esto, podes tomar accións contra %s:</string>
<string name="unfollow_user">Deixar de seguir a %s</string>
<string name="unfollow">Deixar de seguir</string>
<string name="mute_user_explain">Non verás as súas publicacións. Poderá seguirte e ver as túas publicacións e non saberá que a silenciaches.</string>
<string name="block_user_explain">Non vas ver as súas publicacións. Nin verá as túas publicacións nin poderá seguirte. Poderá comprobar que a bloqueaches.</string>
<string name="report_personal_title">Non queres ver esto?</string>
<string name="report_personal_subtitle">Aquí tes unhas opcións para controlar o que ves en Mastodon:</string>
<string name="back">Volver</string>
<string name="search_communities">Nome do servidor ou URL</string>
<string name="instance_rules_title">Regras do servidor</string>
@@ -153,14 +178,19 @@
<string name="category_tech">Tecnoloxía</string>
<string name="confirm_email_title">Mira na caixa de correo</string>
<!-- %s is the email address -->
<string name="confirm_email_subtitle">Preme na ligazón que che enviamos para verificar a %s. Agardamos por ti.</string>
<string name="confirm_email_didnt_get">Non recibiches unha ligazón?</string>
<string name="resend">Reenviar</string>
<string name="open_email_app">Abrir app de email</string>
<string name="resent_email">Enviado o email de confirmación</string>
<string name="compose_hint">Escribe o que che apeteza</string>
<string name="content_warning">Aviso sobre o contido</string>
<string name="save">Gardar</string>
<string name="add_alt_text">Engadir texto descritivo</string>
<string name="visibility_public">Público</string>
<string name="visibility_followers_only">Só para seguidoras</string>
<string name="visibility_private">Só para as mencionadas</string>
<string name="recent_searches">Recentes</string>
<string name="skip">Omitir</string>
<string name="notification_type_follow">Novas seguidoras</string>
<string name="notification_type_favorite">Favoritas</string>
@@ -169,8 +199,14 @@
<string name="notification_type_poll">Enquisas</string>
<string name="choose_account">Elixir conta</string>
<string name="err_not_logged_in">Primeiro tes que acceder a Mastodon</string>
<plurals name="cant_add_more_than_x_attachments">
<item quantity="one">Non podes engadir máis de %d elemento multimedia</item>
<item quantity="other">Non podes engadir máis de %d elementos multimedia</item>
</plurals>
<string name="media_attachment_unsupported_type">O ficheiro %s é dun tipo non permitido</string>
<string name="media_attachment_too_big">O ficheiro %1$s supera o límite de %2$s MB</string>
<string name="settings_theme">Aparencia</string>
<string name="theme_auto">Seguir ao dispositivo</string>
<string name="theme_light">Claro</string>
<string name="theme_dark">Escuro</string>
<string name="settings_behavior">Comportamento</string>
@@ -183,6 +219,9 @@
<string name="settings_clear_cache">Limpar caché multimedia</string>
<string name="settings_app_version">Mastodon para Android v%1$s (%2$d)</string>
<string name="media_cache_cleared">Baleiramos a memoria caché</string>
<string name="confirm_log_out">Pechar sesión %s?</string>
<string name="sensitive_content_explain">A autora marcou este multimedia como sensible.</string>
<string name="avatar_description">Ir ao perfil de %s</string>
<string name="more_options">Máis opcións</string>
<string name="new_post">Nova publicación</string>
<string name="button_reply">Responder</string>
@@ -198,6 +237,7 @@
<string name="media_viewer">Visor multimedia</string>
<string name="follow_user">Segue a %s</string>
<string name="unfollowed_user">Deixaches de seguir a %s</string>
<string name="followed_user">Estás a seguir a %s</string>
<string name="following_user_requested">Solicitaches seguir a %s</string>
<string name="open_in_browser">Abrir nun navegador</string>
<string name="hide_boosts_from_user">Agochar promocións de @%s</string>
@@ -215,7 +255,13 @@
<string name="error_saving_file">Produciuse un erro ao gardar o ficheiro</string>
<string name="file_saved">Ficheiro gardado</string>
<string name="downloading">Descargando…</string>
<string name="no_app_to_handle_action">Non hai apps para esta acción</string>
<string name="local_timeline">Local</string>
<string name="trending_posts_info_banner">Estas son as publicacións en voga en Mastodon.</string>
<string name="trending_links_info_banner">Estas son as novas historias das que se está a falar en Mastodon.</string>
<!-- %s is the server domain -->
<string name="local_timeline_info_banner">Estas son as publicacións das usuarias do teu servidor (%s).</string>
<string name="recommended_accounts_info_banner">Poderían interesarche estas contas en función doutras que segues.</string>
<string name="see_new_posts">Ver novas publicacións</string>
<string name="load_missing_posts">Cargar publicacións que faltan</string>
<string name="follow_back">Seguir tamén</string>
@@ -293,6 +339,7 @@
<string name="login_title">Benvida outra vez</string>
<string name="login_subtitle">Accede co servidor onde creaches a conta.</string>
<string name="server_url">URL do servidor</string>
<string name="signup_random_server_explain">Elixiremos un servidor no teu idioma se segues sen seleccionar nada.</string>
<string name="server_filter_any_language">Calquer idioma</string>
<string name="server_filter_instant_signup">Rexistro Instantáneo</string>
<string name="server_filter_manual_review">Revisión manual</string>
@@ -305,6 +352,7 @@
<string name="server_filter_region_oceania">Oceanía</string>
<string name="not_accepting_new_members">Non se aceptan novas usuarias</string>
<string name="category_special_interests">Intereses Especiais</string>
<string name="signup_passwords_dont_match">Os contrasinais non coinciden</string>
<string name="pick_server_for_me">Elixe por min</string>
<string name="profile_add_row">Engadir fila</string>
<string name="profile_setup">Configuración do perfil</string>
@@ -313,12 +361,14 @@
<string name="popular_on_mastodon">Popular en Mastodon</string>
<string name="follow_all">Seguir a todas</string>
<string name="server_rules_disagree">Non aceptar</string>
<string name="privacy_policy_explanation">Resumo: non recollemos nin procesamos nada.</string>
<!-- %s is server domain -->
<string name="server_policy_disagree">Rexeitar %s</string>
<string name="profile_bio">Biografía</string>
<!-- Shown in a progress dialog when you tap "follow all" -->
<string name="sending_follows">Seguindo usuarias…</string>
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
<string name="signup_email_domain_blocked">%1$s non acepta rexistros desde %2$s. Proba outro ou &lt;a&gt;elixe outro servidor&lt;/a&gt;.</string>
<string name="spoiler_show">Mostrar igualmente</string>
<string name="spoiler_hide">Volver agochar</string>
<string name="poll_multiple_choice">Elixe unha ou varias</string>
@@ -331,22 +381,222 @@
<string name="show">Mostrar</string>
<string name="hide">Agochar</string>
<string name="join_default_server">Únete a %s</string>
<string name="pick_server">Elixe outro servidor</string>
<string name="signup_or_login">ou</string>
<string name="learn_more">Saber máis</string>
<string name="welcome_to_mastodon">Benvida a Mastodon</string>
<string name="welcome_paragraph1">Mastodon é unha rede social descentralizada, onde ningunha empresa ten o control. Está formada por moitos servidores independentes comunicándose entre si.</string>
<string name="what_are_servers">Que son os servidores?</string>
<string name="welcome_paragraph2">Cada conta Mastodon está hospedada nun servidor — cada un coas súas regras, valores e admins. Non importa cal elixas, podes seguir e interactuar con persoas de outros servidores.</string>
<string name="opening_link">Abrindo ligazón…</string>
<string name="link_not_supported">Esta ligazón non está soportada pola app</string>
<string name="log_out_all_accounts">Pechar sesión de todas as contas</string>
<string name="confirm_log_out_all_accounts">Pechar sesión de todas as contas?</string>
<string name="retry">Volver tentar</string>
<string name="post_failed">Fallou o envío da publicación</string>
<!-- %s is formatted file size ("467 KB image") -->
<string name="attachment_description_image">%s imaxe</string>
<string name="attachment_description_video">%s vídeo</string>
<string name="attachment_description_audio">%s audio</string>
<string name="attachment_description_unknown">%s ficheiro</string>
<string name="attachment_type_image">Imaxe</string>
<string name="attachment_type_video">Vídeo</string>
<string name="attachment_type_audio">Audio</string>
<string name="attachment_type_gif">GIF</string>
<string name="attachment_type_unknown">Ficheiro</string>
<string name="attachment_x_percent_uploaded">%d%% subido</string>
<string name="add_poll_option">Engadir opción na enquisa</string>
<string name="poll_length">Lonxitude da enquisa</string>
<string name="poll_style">Estilo</string>
<string name="compose_poll_single_choice">Escolla simple</string>
<string name="compose_poll_multiple_choice">Escolla múltiple</string>
<string name="delete_poll_option">Eliminar opción da enquisa</string>
<string name="poll_style_title">Estilo da enquisa</string>
<string name="alt_text">Texto Alt</string>
<string name="help">Axuda</string>
<string name="what_is_alt_text">Que é o Text Alt?</string>
<string name="alt_text_help">O Text Alt proporciona descrición das imaxes para as persoas con deficiencias visuais, conexións a internet de baixa calidade ou para engadir contexto ás mesmas.\n\nPodes mellorar a accesibilidade e a comprensión da publicación ao escribir un texto alternativo claro, conciso e obxectivo.\n\n<ul><li>Identifica os elementos importantes</li>\n<li>Inclúe o texto que apareza nas imaxes</li>\n<li>Utiliza sintaxe estándar nas frases</li>\n<li>Evita información redundante</li>\n<li>Céntrate nos elementos principais cando sexan imaxes complexas (como diagramas ou mapas)</li></ul></string>
<string name="edit_post">Editar publicación</string>
<string name="no_verified_link">Ligazón non verificada</string>
<string name="compose_autocomplete_emoji_empty">Ver emoji</string>
<string name="compose_autocomplete_users_empty">Atopa as persoas que buscas</string>
<string name="no_search_results">Non atopamos nada con estos termos</string>
<string name="language">Idioma</string>
<string name="language_default">Por defecto</string>
<string name="language_system">Sistema</string>
<string name="language_detecting">Detección do idioma</string>
<string name="language_cant_detect">Non se identificou o idioma</string>
<string name="language_detected">Identificado</string>
<string name="media_hidden">Multimedia oculto</string>
<string name="post_hidden">Publicación oculta</string>
<string name="report_title_post">Denunciar publicación</string>
<string name="forward_report_explanation">A conta é doutro servidor. Enviar unha copia anónima da denuncia aló tamén?</string>
<!-- %s is the server domain -->
<string name="forward_report_to_server">Reenviar a %s</string>
<!-- Shown on the "stamp" on the screen that appears after you report a post/user. Please keep the translation short, preferably a single word -->
<string name="reported">Denunciado</string>
<string name="report_unfollow_explanation">Retira o seguimento para non ver máis as súas publicacións na cronoloxía de inicio.</string>
<string name="muted_user">%s foi acalada</string>
<string name="report_sent_already_blocked">Xa bloqueaches a esta usuaria, non tes que facer nada máis ata que revisemos a túa denuncia.</string>
<string name="report_personal_already_blocked">Xa bloqueaches a esta usuaria, non tes que facer nada máis.\n\nGrazas por axudarnos a facer de Mastodon un lugar seguro!</string>
<string name="blocked_user">Bloqueaches a %s</string>
<string name="mark_all_notifications_read">Marcar todo como lido</string>
<string name="settings_display">Mostar</string>
<string name="settings_filters">Filtros</string>
<string name="settings_server_explanation">Vista xeral, regras, moderación</string>
<!-- %s is the app name (Mastodon, key app_name). I made it a placeholder so everything Just Works™ with forks -->
<string name="about_app">Acerca de %s</string>
<string name="default_post_language">Idioma por defecto da publicación</string>
<string name="settings_alt_text_reminders">Lembrar engadir Texto Alt</string>
<string name="settings_confirm_unfollow">Preguntar antes de deixar de seguir</string>
<string name="settings_confirm_boost">Preguntar antes de promover</string>
<string name="settings_confirm_delete_post">Preguntar antes de borrar publicacións</string>
<string name="pause_all_notifications">Deter todo</string>
<string name="pause_notifications_off">Apagado</string>
<string name="notifications_policy_anyone">Calquera</string>
<string name="notifications_policy_followed">Persoas que te seguen</string>
<string name="notifications_policy_follower">Persoas que segues</string>
<string name="notifications_policy_no_one">Ninguén</string>
<string name="settings_notifications_policy">Recibir notificacións de</string>
<string name="notification_type_mentions_and_replies">Mencións e respostas</string>
<string name="pause_all_notifications_title">Deter todas as notificacións</string>
<plurals name="x_weeks">
<item quantity="one">%d semana</item>
<item quantity="other">%d semanas</item>
</plurals>
<!-- %1$s is the date (may be relative, e.g. "today" or "yesterday"), %2$s is the time. You can reorder these placeholders if that works better for your language -->
<string name="date_at_time">%1$s ás %2$s</string>
<string name="today">hoxe</string>
<string name="yesterday">onte</string>
<string name="tomorrow">mañá</string>
<!-- %s is the timestamp ("tomorrow at 12:34") -->
<string name="pause_notifications_ends">Remata en %s</string>
<!-- %s is the timestamp ("tomorrow at 12:34") -->
<string name="pause_notifications_banner">As notificacións volven %s.</string>
<string name="resume_notifications_now">Reactivar agora</string>
<string name="open_system_notification_settings">Ir aos axustes das notificacións</string>
<string name="about_server">Acerca de</string>
<string name="server_rules">Regras</string>
<string name="server_administrator">Administración</string>
<string name="send_email_to_server_admin">Mensaxe a Admin</string>
<string name="notifications_disabled_in_system">Activar notificacións nos axustes do dispositivo para ver todas as actualizacións.</string>
<string name="settings_even_more">Máis axustes</string>
<string name="settings_show_cws">Mostrar avisos sobre o contido</string>
<string name="settings_hide_sensitive_media">Agochar multimedia sensible</string>
<string name="settings_show_interaction_counts">Conta das interaccións</string>
<string name="settings_show_emoji_in_names">Emoji persoal nos nomes públicos</string>
<plurals name="in_x_seconds">
<item quantity="one">en %d segundo</item>
<item quantity="other">en %d segundos</item>
</plurals>
<plurals name="in_x_minutes">
<item quantity="one">en %d minuto</item>
<item quantity="other">en %d minutos</item>
</plurals>
<plurals name="in_x_hours">
<item quantity="one">en %d hora</item>
<item quantity="other">en %d horas</item>
</plurals>
<plurals name="x_hours_ago">
<item quantity="one">fai %d hora</item>
<item quantity="other">fai %d horas</item>
</plurals>
<string name="alt_text_reminder_title">O multimedia non ten Texto Alt</string>
<plurals name="alt_text_reminder_x_images">
<item quantity="one">%s das imaxes non ten Alt Text. Publicar?</item>
<item quantity="other">%s das imaxes non teñen Alt Text. Publicar?</item>
</plurals>
<plurals name="alt_text_reminder_x_attachments">
<item quantity="one">%s dos anexos multimedia non ten Alt Text. Publicar?</item>
<item quantity="other">%s dos anexos multimedia non teñen Alt Text. Publicar?</item>
</plurals>
<string name="count_one">Un</string>
<string name="count_two">Dous</string>
<string name="count_three">Tres</string>
<string name="count_four">Catro</string>
<string name="alt_text_reminder_post_anyway">Publicar</string>
<!-- %s is the username -->
<string name="unfollow_confirmation">Deixar de seguir a %s?</string>
<string name="filter_active">Activa</string>
<string name="filter_inactive">Inactiva</string>
<string name="settings_add_filter">Engadir filtro</string>
<string name="settings_edit_filter">Editar filtro</string>
<string name="settings_filter_duration">Duración</string>
<string name="settings_filter_muted_words">Palabras acaladas</string>
<string name="settings_filter_context">Acalar desde</string>
<string name="settings_filter_show_cw">Mostrar cun aviso sobre o contido</string>
<string name="settings_filter_show_cw_explanation">Mostrar publicacións incluso se cumplen co filtro, pero detrás dun aviso</string>
<string name="settings_delete_filter">Eliminar filtro</string>
<string name="filter_duration_forever">Para sempre</string>
<!-- %s is the timestamp ("tomorrow at 12:34") -->
<string name="settings_filter_ends">Remata %s</string>
<plurals name="settings_x_muted_words">
<item quantity="one">%d palabra ou frase acalada</item>
<item quantity="other">%d palabras ou frases acaladas</item>
</plurals>
<string name="selection_2_options">%1$s e %2$s</string>
<string name="selection_3_options">%1$s, %2$s e %3$s</string>
<string name="selection_4_or_more">%1$s,%2$s e outras %3$d</string>
<string name="filter_context_home_lists">Inicio &amp; listas</string>
<string name="filter_context_notifications">Notificacións</string>
<string name="filter_context_public_timelines">Cronoloxías públicas</string>
<string name="filter_context_threads_replies">Conversas &amp; respostas</string>
<string name="filter_context_profiles">Perfís</string>
<string name="settings_filter_title">Título</string>
<string name="settings_delete_filter_title">Eliminar filtro \"%s\"?</string>
<string name="settings_delete_filter_confirmation">Vaise eliminar este filtro da túa conta en todos os teus dispositivos.</string>
<string name="add_muted_word">Engadir palabra para acalar</string>
<string name="edit_muted_word">Editar palabra acalada</string>
<string name="add">Engadir</string>
<string name="filter_word_or_phrase">Palabra ou frase</string>
<string name="filter_add_word_help">As palabras non distinguen as maiúsculas e compara a palabra completa.\n\nSe o filtro compara \"Pataca\", agochará tanto \"pataca\" como \"pATaca\" pero non \"patacaza\".</string>
<string name="settings_delete_filter_word">Eliminar palabra \"%s\"?</string>
<string name="enter_selection_mode">Escoller</string>
<string name="select_all">Escoller todo</string>
<string name="settings_filter_duration_title">Duración do filtro</string>
<string name="filter_duration_custom">Personalizado</string>
<plurals name="settings_delete_x_filter_words">
<item quantity="one">Eliminar %d palabra?</item>
<item quantity="other">Eliminar %d palabras?</item>
</plurals>
<plurals name="x_items_selected">
<item quantity="one">%d seleccionado</item>
<item quantity="other">%d seleccionados</item>
</plurals>
<string name="required_form_field_blank">Non pode estar baleiro</string>
<string name="filter_word_already_in_list">Xa está na lista</string>
<string name="app_update_ready">Actualización preparada</string>
<string name="app_update_version">Versión %s</string>
<string name="downloading_update">Descargando (%d%%)</string>
<!-- Shown like a content warning, %s is the name of the filter -->
<string name="post_matches_filter_x">Concorda co filtro “%s”</string>
<string name="search_mastodon">Buscar en Mastodon</string>
<string name="clear_all">Limpar todo</string>
<string name="search_open_url">Abrir URL en Mastodon</string>
<string name="posts_matching_hashtag">Publicacións con \"%s\"</string>
<string name="search_go_to_account">Ir a %s</string>
<string name="posts_matching_string">Publicacións con “%s”</string>
<string name="accounts_matching_string">Persoas con “%s”</string>
<!-- Shown in the post header. Please keep it short -->
<string name="time_seconds_ago_short">fai %d seg.</string>
<string name="time_minutes_ago_short">fai %d min</string>
<string name="time_hours_ago_short">fai %d horas</string>
<string name="time_days_ago_short">hai %d días</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Traducir do %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Traducido do %1$s usando %2$s</string>
<string name="translation_show_original">Mostrar o orixinal</string>
<string name="translation_failed">Fallou a tradución. É posible que a administración non activase a tradución neste servidor ou que o servidor teña unha versión antiga de Mastodon que non ten soporte para a tradución.</string>
<string name="settings_privacy">Privacidade e alcance</string>
<string name="settings_discoverable">Perfil destacado e publicacións nos algoritmos de descubrimento</string>
<string name="settings_indexable">Incluír publicacións públicas nos resultados das buscas</string>
<plurals name="x_participants">
<item quantity="one">%,d participante</item>
<item quantity="other">%,d participantes</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="one">%,d publicación hoxe</item>
<item quantity="other">%,d publicacións hoxe</item>
</plurals>
</resources>

View File

@@ -13,6 +13,7 @@
<string name="user_sent_follow_request">%s հետեւելու հարցում է ուղարկել</string>
<string name="user_favorited">%s-ը հավանեց ձեր գրառումը</string>
<string name="notification_boosted">%s տարածեց ձեր գրառումը</string>
<string name="poll_ended">Տեսեք ձեր քվեարկած հարցման արդյունքները</string>
<string name="share_toot_title">Տարածել</string>
<string name="settings">Կարգավորումներ</string>
<string name="publish">Հրապարակել</string>
@@ -102,6 +103,7 @@
<string name="deleting">Ջնջում…</string>
<string name="play">Նվագարկել</string>
<string name="pause">Դադար տալ</string>
<string name="log_out">Ելք</string>
<string name="add_account">Ավելացնել հաշիվ</string>
<string name="search_hint">Որոնել</string>
<string name="hashtags">Պիտակներ</string>

View File

@@ -554,5 +554,18 @@
<string name="time_hours_ago_short">%dj yang lalu</string>
<string name="time_days_ago_short">%dh yang lalu</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Terjemahkan dari bahasa %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Diterjemahkan dari bahasa %1$s menggunakan %2$s</string>
<string name="translation_show_original">Tampilkan yang asli</string>
<string name="translation_failed">Terjemahan gagal. Administrator mungkin belum mengaktifkan terjemahan di server ini atau server ini menjalankan Mastodon versi lama yang belum mendukung terjemahan.</string>
<string name="settings_privacy">Privasi dan jangkauan</string>
<string name="settings_discoverable">Fiturkan profil dan kiriman dalam algoritma penjelajahan</string>
<string name="settings_indexable">Sertakan kiriman publik dalam hasil pencarian</string>
<plurals name="x_participants">
<item quantity="other">%,d peserta</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="other">%,d kiriman hari ini</item>
</plurals>
</resources>

View File

@@ -583,5 +583,20 @@
<string name="time_hours_ago_short">fyrir %dh síðan</string>
<string name="time_days_ago_short">fyrir %dd síðan</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Þýða úr %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Þýtt úr %1$s með %2$s</string>
<string name="translation_show_original">Sýna upprunalegt</string>
<string name="translation_failed">Þýðing mistókst. Mögulega hefur kerfisstjórinn ekki virkjað þýðingar á þessum netþjóni, eða að netþjónninn sé keyrður á eldri útgáfu Mastodon þar sem þýðingar séu ekki studdar.</string>
<string name="settings_privacy">Gagnaleynd og útbreiðsla</string>
<string name="settings_discoverable">Hafa notandasnið og færslur með í reikniritum leitar</string>
<string name="settings_indexable">Hafa opinberar færslur með í leitarniðurstöðum</string>
<plurals name="x_participants">
<item quantity="one">%,d þátttakandi</item>
<item quantity="other">%,d þátttakendur</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="one">%,d færsla í dag</item>
<item quantity="other">%,d færslur í dag</item>
</plurals>
</resources>

View File

@@ -588,6 +588,7 @@
<string name="post_translated">Tradotto da %1$s utilizzando %2$s</string>
<string name="translation_show_original">Mostra originale</string>
<string name="translation_failed">Traduzione fallita. Forse l\'amministratore non ha abilitato le traduzioni su questo server, o su questo server è in esecuzione una versione precedente di Mastodon in cui le traduzioni non sono ancora supportate.</string>
<string name="settings_indexable">Includi i post pubblici nei risultati di ricerca</string>
<plurals name="x_participants">
<item quantity="one">%,d participante</item>
<item quantity="other">%,d partecipanti</item>

View File

@@ -554,5 +554,18 @@
<string name="time_hours_ago_short">%d 時間前</string>
<string name="time_days_ago_short">%d 日前</string>
<!-- %s is the name of the post language -->
<string name="translate_post">%s から翻訳</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">%2$s による %1$s からの翻訳</string>
<string name="translation_show_original">原文を表示</string>
<string name="translation_failed">翻訳に失敗しました。このサーバーは翻訳機能を有効にしていないか、翻訳機能のない旧バージョンの Mastodon を実行しているのかもしれません。</string>
<string name="settings_privacy">プライバシーとつながりやすさ</string>
<string name="settings_discoverable">アカウントを見つけやすくする</string>
<string name="settings_indexable">公開投稿を検索できるようにする</string>
<plurals name="x_participants">
<item quantity="other">参加者 %d 人</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="other">今日の投稿 %,d 件</item>
</plurals>
</resources>

View File

@@ -572,5 +572,15 @@
<string name="time_hours_ago_short">%dh atrás</string>
<string name="time_days_ago_short">%dd atrás</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Traduzido de %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Traduzido de %1$s usando %2$s</string>
<string name="translation_show_original">Mostrar original</string>
<string name="translation_failed">A tradução falhou. Talvez o administrador não tenha habilitado as traduções neste servidor ou este servidor esteja executando uma versão mais antiga do Mastodon onde as traduções ainda não são suportadas.</string>
<string name="settings_privacy">Privacidade e alcance</string>
<string name="settings_indexable">Incluir publicações públicas nos resultados de pesquisa</string>
<plurals name="x_participants">
<item quantity="one">%,d participante</item>
<item quantity="other">%,d participantes</item>
</plurals>
</resources>

View File

@@ -641,5 +641,24 @@
<string name="time_hours_ago_short">%d ч. назад</string>
<string name="time_days_ago_short">%d д. назад</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Перевести %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">%1$s переведён с помощью %2$s</string>
<string name="translation_show_original">Показать оригинал</string>
<string name="translation_failed">Перевод не удался. Возможно, администратор не включил переводы на этом сервере или на этом сервере установлена ​​более старая версия Mastodon, где переводы еще не поддерживаются.</string>
<string name="settings_privacy">Приватность и доступ</string>
<string name="settings_discoverable">Показывать профиль и посты в алгоритмах рекомендаций</string>
<string name="settings_indexable">Включить публичные посты в результаты поиска</string>
<plurals name="x_participants">
<item quantity="one">%,d участник</item>
<item quantity="few">%,d участника</item>
<item quantity="many">%,d участников</item>
<item quantity="other">%,d участников</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="one">%,d пост сегодня</item>
<item quantity="few">%,d поста сегодня</item>
<item quantity="many">%,d постов сегодня</item>
<item quantity="other">%,d постов сегодня</item>
</plurals>
</resources>

View File

@@ -11,7 +11,7 @@
<string name="discard">ඉවතලන්න</string>
<string name="cancel">අවලංගු</string>
<string name="media">මාධ්‍ය</string>
<string name="profile_about">පිිබඳව</string>
<string name="profile_about">පිිබඳව</string>
<string name="edit_profile">පැතිකඩ සංස්කරණය</string>
<string name="mute_user">%s නිහඬ</string>
<string name="unmute_user">%s නොනිහඬ</string>

View File

@@ -274,6 +274,8 @@
<string name="trending_posts_info_banner">To so objave, ki plenijo pozornost po Mastodonu.</string>
<string name="trending_links_info_banner">To so novice, o katerih se govori na Mastodonu.</string>
<!-- %s is the server domain -->
<string name="local_timeline_info_banner">To so vse objave vseh uporabnikov na vašem strežniku (%s).</string>
<string name="recommended_accounts_info_banner">Glede na to, komu sledite, vam bodo ti računi všeč.</string>
<string name="see_new_posts">Pokaži nove objave</string>
<string name="load_missing_posts">Naloži manjkajoče objave</string>
<string name="follow_back">Sledijo nazaj</string>
@@ -455,8 +457,11 @@
<!-- %s is the app name (Mastodon, key app_name). I made it a placeholder so everything Just Works™ with forks -->
<string name="about_app">O programu %s</string>
<string name="default_post_language">Privzeti jezik objave</string>
<string name="settings_confirm_delete_post">Vprašaj pred brisanjem objav</string>
<string name="pause_all_notifications">Premor za vse</string>
<string name="pause_notifications_off">Izklopljeno</string>
<string name="notifications_policy_anyone">Kdor koli</string>
<string name="notifications_policy_followed">Ljudje, ki vam sledijo</string>
<string name="notifications_policy_follower">Ljudje, ki jim sledite</string>
<string name="notifications_policy_no_one">Nihče</string>
<string name="notification_type_mentions_and_replies">Omembe in odgovori</string>
@@ -504,6 +509,7 @@
<string name="filter_context_profiles">Profili</string>
<string name="settings_filter_title">Naslov</string>
<string name="settings_delete_filter_title">Ali želite izbrisati filter »%s«?</string>
<string name="settings_delete_filter_confirmation">Ta filter bo izbrisan iz vašega računa na vseh vaših napravah.</string>
<string name="add_muted_word">Dodaj utišano besedo</string>
<string name="edit_muted_word">Uredi utišano besedo</string>
<string name="add">Dodaj</string>
@@ -533,5 +539,12 @@
<string name="time_hours_ago_short">pred %dh urami</string>
<string name="time_days_ago_short">pred %d dnemi</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Prevedi iz jezika: %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Prevedeno iz %1$s s pomočjo %2$s</string>
<string name="translation_show_original">Pokaži izvirnik</string>
<string name="translation_failed">Prevod je spodletel. Morda skrbnik ni omogočil prevajanja na tem strežniku ali pa strežnik teče na starejši različici Masotodona, na kateri prevajanje še ni podprto.</string>
<string name="settings_privacy">Zasebnost in dosegljivost</string>
<string name="settings_discoverable">Izpostavljaj profile in objave v algoritmih odkrivanja</string>
<string name="settings_indexable">Med zadetke iskanja vključi javne objave</string>
</resources>

View File

@@ -559,6 +559,9 @@
<string name="post_translated">แปลจาก %1$s โดยใช้ %2$s</string>
<string name="translation_show_original">แสดงดั้งเดิม</string>
<string name="translation_failed">การแปลล้มเหลว บางทีผู้ดูแลอาจไม่ได้เปิดใช้งานการแปลในเซิร์ฟเวอร์นี้หรือเซิร์ฟเวอร์นี้กำลังใช้ Mastodon รุ่นเก่ากว่าที่ยังไม่รองรับการแปล</string>
<string name="settings_privacy">ความเป็นส่วนตัวและการเข้าถึง</string>
<string name="settings_discoverable">แสดงโปรไฟล์และโพสต์ในอัลกอริทึมการค้นพบ</string>
<string name="settings_indexable">รวมโพสต์สาธารณะในผลลัพธ์การค้นหา</string>
<plurals name="x_participants">
<item quantity="other">%,d ผู้มีส่วนร่วม</item>
</plurals>

View File

@@ -387,6 +387,7 @@
<string name="welcome_to_mastodon">Mastodon\'a hoş geldiniz</string>
<string name="welcome_paragraph1">Mastodon merkezi olmayan bir sosyal ağdır, yani onu tek bir şirket kontrol etmiyor. Hepsi birbirine bağlı, bağımsız olarak çalışan birçok sunucudan oluşur.</string>
<string name="what_are_servers">Sunucular nedir?</string>
<string name="welcome_paragraph2">Her Mastodon hesabı bir sunucuda barındırılır - her birinin kendi değerleri, kuralları ve yöneticileri vardır. Hangisini seçerseniz seçin, herhangi bir sunucudaki insanları takip edebilir ve onlarla etkileşime geçebilirsiniz.</string>
<string name="opening_link">Bağlantıılıyor…</string>
<string name="link_not_supported">Bu bağlantı uygulamada desteklenmiyor</string>
<string name="log_out_all_accounts">Tüm hesaplardan çıkış yap</string>
@@ -582,5 +583,20 @@
<string name="time_hours_ago_short">%dsa önce</string>
<string name="time_days_ago_short">%dg önce</string>
<!-- %s is the name of the post language -->
<string name="translate_post">%s dilinden çevrildi</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">%2$s kullanılarak %1$s dilinden çevrildi</string>
<string name="translation_show_original">Özgün içeriği göster</string>
<string name="translation_failed">Çeviri başarısız oldu. Yönetici bu sunucuda çevirileri etkinleştirmemiş olabilir veya bu sunucu çevirilerin henüz desteklenmediği eski bir Mastodon sürümünü çalıştırıyor olabilir.</string>
<string name="settings_privacy">Gizlilik ve erişim</string>
<string name="settings_discoverable">Profil ve gönderileri keşif algoritmalarında kullan</string>
<string name="settings_indexable">Herkese açık gönderileri arama sonuçlarına ekle</string>
<plurals name="x_participants">
<item quantity="one">%d katılımcılar</item>
<item quantity="other">%d katılımcılar</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="one">%,d bunu gönder</item>
<item quantity="other">%,d bunları gönder</item>
</plurals>
</resources>

View File

@@ -641,5 +641,24 @@
<string name="time_hours_ago_short">%dгод. тому</string>
<string name="time_days_ago_short">%dд. тому</string>
<!-- %s is the name of the post language -->
<string name="translate_post">Перекласти з %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Перекладено з %1$s за допомогою %2$s</string>
<string name="translation_show_original">Показати оригінал</string>
<string name="translation_failed">Не вдалося виконати переклад. Можливо, адміністратор не активував переклади на цьому сервері або цей сервер використовує стару версію Mastodon, де переклади ще не підтримуються.</string>
<string name="settings_privacy">Приватність і досяжність</string>
<string name="settings_discoverable">Враховувати профіль та дописи в алгоритмах пошуку</string>
<string name="settings_indexable">Включити загальнодоступні дописи в результати пошуку</string>
<plurals name="x_participants">
<item quantity="one">%,d учасник</item>
<item quantity="few">%,d учасники</item>
<item quantity="many">%,d учасників</item>
<item quantity="other">%,d учасника</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="one">%,d допис сьогодні</item>
<item quantity="few">%,d дописи сьогодні</item>
<item quantity="many">%,d дописів сьогодні</item>
<item quantity="other">%,d дописа сьогодні</item>
</plurals>
</resources>

View File

@@ -559,6 +559,9 @@
<string name="post_translated">Dịch từ %1$s bằng %2$s</string>
<string name="translation_show_original">Bản gốc</string>
<string name="translation_failed">Dịch không thành công. Có thể quản trị viên chưa bật dịch trên máy chủ này hoặc máy chủ này đang chạy phiên bản cũ hơn của Mastodon chưa hỗ trợ dịch.</string>
<string name="settings_privacy">Riêng tư và tiếp cận</string>
<string name="settings_discoverable">Cho phép khám phá hồ sơ</string>
<string name="settings_indexable">Cho phép hiện tút công khai trong kết quả tìm kiếm</string>
<plurals name="x_participants">
<item quantity="other">%,d người thảo luận</item>
</plurals>

View File

@@ -553,5 +553,12 @@
<string name="time_hours_ago_short">%d 小时前</string>
<string name="time_days_ago_short">%d 天前</string>
<!-- %s is the name of the post language -->
<string name="translate_post">从 %s 翻译</string>
<!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">从 %1$s 翻译成 %2$s</string>
<string name="translation_show_original">显示原文</string>
<string name="translation_failed">翻译失败。此服务器运行的 Mastodon 版本不支持翻译功能,或管理员未将翻译功能开启。</string>
<string name="settings_privacy">隐私与可达性</string>
<string name="settings_discoverable">在发现算法中展示您的个人资料和嘟文</string>
<string name="settings_indexable">将您的公开嘟文纳入搜索范围</string>
</resources>

View File

@@ -559,6 +559,9 @@
<string name="post_translated">透過 %2$s 翻譯 %1$s</string>
<string name="translation_show_original">顯示原文</string>
<string name="translation_failed">翻譯失敗。也許管理員未於此伺服器啟用翻譯功能,或此伺服器為未支援翻譯功能之舊版本 Mastodon。</string>
<string name="settings_privacy">隱私權及觸及</string>
<string name="settings_discoverable">於探索演算法中推薦個人檔案及嘟文</string>
<string name="settings_indexable">允許公開嘟文顯示於搜尋結果中</string>
<plurals name="x_participants">
<item quantity="other">%,d 位參與者</item>
</plurals>

View File

@@ -608,4 +608,6 @@
<item quantity="one">%,d post today</item>
<item quantity="other">%,d posts today</item>
</plurals>
<string name="error_playing_video">Error playing video</string>
</resources>

View File

@@ -21,6 +21,7 @@
<item name="android:actionModeBackground">@color/m3_sys_light_primary</item>
<item name="android:actionModeStyle">@style/Widget.Mastodon.Toolbar.ActionMode</item>
<item name="android:actionModeCloseDrawable">@drawable/ic_actionmode_close</item>
<item name="appkitEmptyTextAppearance">@style/empty_text</item>
<!-- M3 colors -->
<item name="colorM3Primary">@color/m3_sys_light_primary</item>
@@ -85,6 +86,7 @@
<item name="android:windowActionModeOverlay">true</item>
<item name="android:actionModeBackground">@color/m3_sys_dark_primary</item>
<item name="android:actionModeCloseDrawable">@drawable/ic_actionmode_close</item>
<item name="appkitEmptyTextAppearance">@style/empty_text</item>
<!-- M3 colors -->
<item name="colorM3Primary">@color/m3_sys_dark_primary</item>
@@ -399,4 +401,8 @@
<style name="window_fade_out">
<item name="android:windowExitAnimation">@anim/fade_out_fast</item>
</style>
<style name="empty_text" parent="m3_body_large">
<item name="android:textColor">?colorM3OnSurfaceVariant</item>
</style>
</resources>

View File

@@ -0,0 +1,116 @@
// run: java tools/VerifyTranslatedStringFormatting.java
// Reads all localized strings and makes sure they contain valid formatting placeholders matching the original English strings to avoid crashes.
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class VerifyTranslatedStringFormatting{
// %[argument_index$][flags][width][.precision][t]conversion
private static final String formatSpecifier="%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])";
private static final Pattern fsPattern=Pattern.compile(formatSpecifier);
private static HashMap<String, List<String>> placeholdersInStrings=new HashMap<>();
private static int errorCount=0;
public static void main(String[] args) throws Exception{
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc;
try(FileInputStream in=new FileInputStream("mastodon/src/main/res/values/strings.xml")){
doc=builder.parse(in);
}
NodeList list=doc.getDocumentElement().getChildNodes(); // why does this stupid NodeList thing exist at all?
for(int i=0;i<list.getLength();i++){
if(list.item(i) instanceof Element el){
String name=el.getAttribute("name");
String value;
if("string".equals(el.getTagName())){
value=el.getTextContent();
}else if("plurals".equals(el.getTagName())){
value=el.getElementsByTagName("item").item(0).getTextContent();
}else{
System.out.println("Warning: unexpected tag "+name);
continue;
}
ArrayList<String> placeholders=new ArrayList<>();
Matcher matcher=fsPattern.matcher(value);
while(matcher.find()){
placeholders.add(matcher.group());
}
placeholdersInStrings.put(name, placeholders);
}
}
for(File file:new File("mastodon/src/main/res").listFiles()){
if(file.getName().startsWith("values-")){
File stringsXml=new File(file, "strings.xml");
if(stringsXml.exists()){
processFile(stringsXml);
}
}
}
if(errorCount>0){
System.err.println("Found "+errorCount+" problems in localized strings");
System.exit(1);
}
}
private static void processFile(File file) throws Exception{
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc;
try(FileInputStream in=new FileInputStream(file)){
doc=builder.parse(in);
}
NodeList list=doc.getDocumentElement().getChildNodes();
for(int i=0;i<list.getLength();i++){
if(list.item(i) instanceof Element el){
String name=el.getAttribute("name");
String value;
if("string".equals(el.getTagName())){
value=el.getTextContent();
if(!verifyString(value, placeholdersInStrings.get(name))){
errorCount++;
System.out.println(file+": string "+name+" is missing placeholders");
}
}else if("plurals".equals(el.getTagName())){
NodeList items=el.getElementsByTagName("item");
for(int j=0;j<items.getLength();j++){
Element item=(Element)items.item(j);
value=item.getTextContent();
String quantity=item.getAttribute("quantity");
if(!verifyString(value, placeholdersInStrings.get(name))){
// Some languages use zero/one/two for just these numbers so they may skip the placeholder
// still make sure that there's no '%' characters to avoid crashes
if(List.of("zero", "one", "two").contains(quantity) && !value.contains("%")){
continue;
}
errorCount++;
System.out.println(file+": string "+name+"["+quantity+"] is missing placeholders");
}
}
}else{
System.out.println("Warning: unexpected tag "+name);
continue;
}
}
}
}
private static boolean verifyString(String str, List<String> placeholders){
for(String placeholder:placeholders){
if(placeholder.equals("%,d")){
// %,d and %d are interchangeable but %,d provides nicer formatting
if(!str.contains(placeholder) && !str.contains("%d"))
return false;
}else if(!str.contains(placeholder)){
return false;
}
}
return true;
}
}