diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java index 0ed346baf..8bc8b4465 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java @@ -1,5 +1,7 @@ package org.joinmastodon.android.fragments; +import static org.joinmastodon.android.utils.MastodonLanguage.allLanguages; + import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.Activity; @@ -96,6 +98,7 @@ import org.joinmastodon.android.ui.views.ComposeEditText; import org.joinmastodon.android.ui.views.ComposeMediaLayout; import org.joinmastodon.android.ui.views.ReorderableLinearLayout; import org.joinmastodon.android.ui.views.SizeListenerLinearLayout; +import org.joinmastodon.android.utils.MastodonLanguage; import org.parceler.Parcel; import org.parceler.Parcels; @@ -104,8 +107,6 @@ import java.net.SocketException; import java.net.UnknownHostException; import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Locale; import java.util.UUID; @@ -133,7 +134,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr // from https://github.com/mastodon/mastodon-ios/blob/main/Mastodon/Helper/MastodonRegex.swift private static final Pattern AUTO_COMPLETE_PATTERN=Pattern.compile("(? allIsoLanguages; @SuppressLint("NewApi") // this class actually exists on 6.0 private final BreakIterator breakIterator=BreakIterator.getCharacterInstance(); @@ -190,22 +190,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr private Runnable updateUploadEtaRunnable; private String language; - - static { - Locale[] locales = Locale.getAvailableLocales(); - List allLocales = new ArrayList<>(); - List addedLanguages = new ArrayList<>(); - for (Locale locale : locales) { - String lang = locale.getLanguage(); - if (!addedLanguages.contains(lang)) { - allLocales.add(locale); - addedLanguages.add(lang); - } - } - - Collections.sort(allLocales, Comparator.comparing(l -> l.getDisplayLanguage(Locale.getDefault()))); - allIsoLanguages = allLocales; - } + private MastodonLanguage.LanguageResolver languageResolver; @Override public void onCreate(Bundle savedInstanceState){ @@ -218,6 +203,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr instanceDomain=session.domain; customEmojis=AccountSessionManager.getInstance().getCustomEmojis(instanceDomain); instance=AccountSessionManager.getInstance().getInstanceInfo(instanceDomain); + languageResolver=new MastodonLanguage.LanguageResolver(instance); if(getArguments().containsKey("editStatus")){ editingStatus=Parcels.unwrap(getArguments().getParcelable("editStatus")); } @@ -610,13 +596,13 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr } private void updateLanguage(String lang) { - updateLanguage(new Locale(lang)); + updateLanguage(languageResolver.from(lang)); } - private void updateLanguage(Locale loc) { + private void updateLanguage(MastodonLanguage loc) { language = loc.getLanguage(); - languageButton.setText(loc.getDisplayLanguage(loc)); - languageButton.setContentDescription(getActivity().getString(R.string.post_language, loc.getDisplayLanguage(Locale.getDefault()))); + languageButton.setText(loc.getLanguageName()); + languageButton.setContentDescription(getActivity().getString(R.string.post_language, loc.getDefaultName())); } @SuppressLint("ClickableViewAccessibility") @@ -631,7 +617,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr languageButton.setCompoundDrawableTintList(languageButton.getTextColors()); languageButton.setCompoundDrawablePadding(V.dp(6)); - updateLanguage(Locale.getDefault()); + updateLanguage(languageResolver.getDefault()); languagePopup=new PopupMenu(getActivity(), languageButton); languageButton.setOnTouchListener(languagePopup.getDragToOpenListener()); languageButton.setOnClickListener(v->languagePopup.show()); @@ -639,19 +625,19 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr Menu languageMenu = languagePopup.getMenu(); for (String recentLanguage : GlobalUserPreferences.recentLanguages) { - Locale loc = new Locale(recentLanguage); - languageMenu.add(0, allIsoLanguages.indexOf(loc), Menu.NONE, loc.getDisplayLanguage(Locale.getDefault())); + MastodonLanguage l = languageResolver.from(recentLanguage); + languageMenu.add(0, allLanguages.indexOf(l), Menu.NONE, getActivity().getString(R.string.language_name, l.getDefaultName(), l.getLanguageName())); } SubMenu allLanguagesMenu = languageMenu.addSubMenu(R.string.all_languages); - for (int i = 0; i < allIsoLanguages.size(); i++) { - Locale loc = allIsoLanguages.get(i); - allLanguagesMenu.add(0, i, Menu.NONE, loc.getDisplayLanguage(Locale.getDefault())); + for (int i = 0; i < allLanguages.size(); i++) { + MastodonLanguage l = allLanguages.get(i); + allLanguagesMenu.add(0, i, Menu.NONE, getActivity().getString(R.string.language_name, l.getDefaultName(), l.getLanguageName())); } languagePopup.setOnMenuItemClickListener(i->{ if (i.hasSubMenu()) return false; - updateLanguage(allIsoLanguages.get(i.getItemId())); + updateLanguage(allLanguages.get(i.getItemId())); return true; }); diff --git a/mastodon/src/main/java/org/joinmastodon/android/utils/MastodonLanguage.java b/mastodon/src/main/java/org/joinmastodon/android/utils/MastodonLanguage.java new file mode 100644 index 000000000..b0b19e72c --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/utils/MastodonLanguage.java @@ -0,0 +1,82 @@ + +package org.joinmastodon.android.utils; + +import static org.joinmastodon.android.api.MastodonAPIController.gson; + +import org.joinmastodon.android.model.Instance; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +public class MastodonLanguage { + // On an up-to-date Mastodon instance: + // copy(JSON.stringify(JSON.stringify(JSON.parse(document.getElementById('initial-state').textContent).languages))) + public static String languagesJson = + "[[\"aa\",\"Afar\",\"Afaraf\"],[\"ab\",\"Abkhaz\",\"аҧсуа бызшәа\"],[\"ae\",\"Avestan\",\"avesta\"],[\"af\",\"Afrikaans\",\"Afrikaans\"],[\"ak\",\"Akan\",\"Akan\"],[\"am\",\"Amharic\",\"አማርኛ\"],[\"an\",\"Aragonese\",\"aragonés\"],[\"ar\",\"Arabic\",\"اللغة العربية\"],[\"as\",\"Assamese\",\"অসমীয়া\"],[\"av\",\"Avaric\",\"авар мацӀ\"],[\"ay\",\"Aymara\",\"aymar aru\"],[\"az\",\"Azerbaijani\",\"azərbaycan dili\"],[\"ba\",\"Bashkir\",\"башҡорт теле\"],[\"be\",\"Belarusian\",\"беларуская мова\"],[\"bg\",\"Bulgarian\",\"български език\"],[\"bh\",\"Bihari\",\"भोजपुरी\"],[\"bi\",\"Bislama\",\"Bislama\"],[\"bm\",\"Bambara\",\"bamanankan\"],[\"bn\",\"Bengali\",\"বাংলা\"],[\"bo\",\"Tibetan\",\"བོད་ཡིག\"],[\"br\",\"Breton\",\"brezhoneg\"],[\"bs\",\"Bosnian\",\"bosanski jezik\"],[\"ca\",\"Catalan\",\"Català\"],[\"ce\",\"Chechen\",\"нохчийн мотт\"],[\"ch\",\"Chamorro\",\"Chamoru\"],[\"co\",\"Corsican\",\"corsu\"],[\"cr\",\"Cree\",\"ᓀᐦᐃᔭᐍᐏᐣ\"],[\"cs\",\"Czech\",\"čeština\"],[\"cu\",\"Old Church Slavonic\",\"ѩзыкъ словѣньскъ\"],[\"cv\",\"Chuvash\",\"чӑваш чӗлхи\"],[\"cy\",\"Welsh\",\"Cymraeg\"],[\"da\",\"Danish\",\"dansk\"],[\"de\",\"German\",\"Deutsch\"],[\"dv\",\"Divehi\",\"Dhivehi\"],[\"dz\",\"Dzongkha\",\"རྫོང་ཁ\"],[\"ee\",\"Ewe\",\"Eʋegbe\"],[\"el\",\"Greek\",\"Ελληνικά\"],[\"en\",\"English\",\"English\"],[\"eo\",\"Esperanto\",\"Esperanto\"],[\"es\",\"Spanish\",\"Español\"],[\"et\",\"Estonian\",\"eesti\"],[\"eu\",\"Basque\",\"euskara\"],[\"fa\",\"Persian\",\"فارسی\"],[\"ff\",\"Fula\",\"Fulfulde\"],[\"fi\",\"Finnish\",\"suomi\"],[\"fj\",\"Fijian\",\"Vakaviti\"],[\"fo\",\"Faroese\",\"føroyskt\"],[\"fr\",\"French\",\"Français\"],[\"fy\",\"Western Frisian\",\"Frysk\"],[\"ga\",\"Irish\",\"Gaeilge\"],[\"gd\",\"Scottish Gaelic\",\"Gàidhlig\"],[\"gl\",\"Galician\",\"galego\"],[\"gu\",\"Gujarati\",\"ગુજરાતી\"],[\"gv\",\"Manx\",\"Gaelg\"],[\"ha\",\"Hausa\",\"هَوُسَ\"],[\"he\",\"Hebrew\",\"עברית\"],[\"hi\",\"Hindi\",\"हिन्दी\"],[\"ho\",\"Hiri Motu\",\"Hiri Motu\"],[\"hr\",\"Croatian\",\"Hrvatski\"],[\"ht\",\"Haitian\",\"Kreyòl ayisyen\"],[\"hu\",\"Hungarian\",\"magyar\"],[\"hy\",\"Armenian\",\"Հայերեն\"],[\"hz\",\"Herero\",\"Otjiherero\"],[\"ia\",\"Interlingua\",\"Interlingua\"],[\"id\",\"Indonesian\",\"Bahasa Indonesia\"],[\"ie\",\"Interlingue\",\"Interlingue\"],[\"ig\",\"Igbo\",\"Asụsụ Igbo\"],[\"ii\",\"Nuosu\",\"ꆈꌠ꒿ Nuosuhxop\"],[\"ik\",\"Inupiaq\",\"Iñupiaq\"],[\"io\",\"Ido\",\"Ido\"],[\"is\",\"Icelandic\",\"Íslenska\"],[\"it\",\"Italian\",\"Italiano\"],[\"iu\",\"Inuktitut\",\"ᐃᓄᒃᑎᑐᑦ\"],[\"ja\",\"Japanese\",\"日本語\"],[\"jv\",\"Javanese\",\"basa Jawa\"],[\"ka\",\"Georgian\",\"ქართული\"],[\"kg\",\"Kongo\",\"Kikongo\"],[\"ki\",\"Kikuyu\",\"Gĩkũyũ\"],[\"kj\",\"Kwanyama\",\"Kuanyama\"],[\"kk\",\"Kazakh\",\"қазақ тілі\"],[\"kl\",\"Kalaallisut\",\"kalaallisut\"],[\"km\",\"Khmer\",\"ខេមរភាសា\"],[\"kn\",\"Kannada\",\"ಕನ್ನಡ\"],[\"ko\",\"Korean\",\"한국어\"],[\"kr\",\"Kanuri\",\"Kanuri\"],[\"ks\",\"Kashmiri\",\"कश्मीरी\"],[\"ku\",\"Kurdish\",\"Kurdî\"],[\"kv\",\"Komi\",\"коми кыв\"],[\"kw\",\"Cornish\",\"Kernewek\"],[\"ky\",\"Kyrgyz\",\"Кыргызча\"],[\"la\",\"Latin\",\"latine\"],[\"lb\",\"Luxembourgish\",\"Lëtzebuergesch\"],[\"lg\",\"Ganda\",\"Luganda\"],[\"li\",\"Limburgish\",\"Limburgs\"],[\"ln\",\"Lingala\",\"Lingála\"],[\"lo\",\"Lao\",\"ລາວ\"],[\"lt\",\"Lithuanian\",\"lietuvių kalba\"],[\"lu\",\"Luba-Katanga\",\"Tshiluba\"],[\"lv\",\"Latvian\",\"latviešu valoda\"],[\"mg\",\"Malagasy\",\"fiteny malagasy\"],[\"mh\",\"Marshallese\",\"Kajin M̧ajeļ\"],[\"mi\",\"Māori\",\"te reo Māori\"],[\"mk\",\"Macedonian\",\"македонски јазик\"],[\"ml\",\"Malayalam\",\"മലയാളം\"],[\"mn\",\"Mongolian\",\"Монгол хэл\"],[\"mr\",\"Marathi\",\"मराठी\"],[\"ms\",\"Malay\",\"Bahasa Melayu\"],[\"mt\",\"Maltese\",\"Malti\"],[\"my\",\"Burmese\",\"ဗမာစာ\"],[\"na\",\"Nauru\",\"Ekakairũ Naoero\"],[\"nb\",\"Norwegian Bokmål\",\"Norsk bokmål\"],[\"nd\",\"Northern Ndebele\",\"isiNdebele\"],[\"ne\",\"Nepali\",\"नेपाली\"],[\"ng\",\"Ndonga\",\"Owambo\"],[\"nl\",\"Dutch\",\"Nederlands\"],[\"nn\",\"Norwegian Nynorsk\",\"Norsk Nynorsk\"],[\"no\",\"Norwegian\",\"Norsk\"],[\"nr\",\"Southern Ndebele\",\"isiNdebele\"],[\"nv\",\"Navajo\",\"Diné bizaad\"],[\"ny\",\"Chichewa\",\"chiCheŵa\"],[\"oc\",\"Occitan\",\"occitan\"],[\"oj\",\"Ojibwe\",\"ᐊᓂᔑᓈᐯᒧᐎᓐ\"],[\"om\",\"Oromo\",\"Afaan Oromoo\"],[\"or\",\"Oriya\",\"ଓଡ଼ିଆ\"],[\"os\",\"Ossetian\",\"ирон æвзаг\"],[\"pa\",\"Panjabi\",\"ਪੰਜਾਬੀ\"],[\"pi\",\"Pāli\",\"पाऴि\"],[\"pl\",\"Polish\",\"Polski\"],[\"ps\",\"Pashto\",\"پښتو\"],[\"pt\",\"Portuguese\",\"Português\"],[\"qu\",\"Quechua\",\"Runa Simi\"],[\"rm\",\"Romansh\",\"rumantsch grischun\"],[\"rn\",\"Kirundi\",\"Ikirundi\"],[\"ro\",\"Romanian\",\"Română\"],[\"ru\",\"Russian\",\"Русский\"],[\"rw\",\"Kinyarwanda\",\"Ikinyarwanda\"],[\"sa\",\"Sanskrit\",\"संस्कृतम्\"],[\"sc\",\"Sardinian\",\"sardu\"],[\"sd\",\"Sindhi\",\"सिन्धी\"],[\"se\",\"Northern Sami\",\"Davvisámegiella\"],[\"sg\",\"Sango\",\"yângâ tî sängö\"],[\"si\",\"Sinhala\",\"සිංහල\"],[\"sk\",\"Slovak\",\"slovenčina\"],[\"sl\",\"Slovenian\",\"slovenščina\"],[\"sn\",\"Shona\",\"chiShona\"],[\"so\",\"Somali\",\"Soomaaliga\"],[\"sq\",\"Albanian\",\"Shqip\"],[\"sr\",\"Serbian\",\"српски језик\"],[\"ss\",\"Swati\",\"SiSwati\"],[\"st\",\"Southern Sotho\",\"Sesotho\"],[\"su\",\"Sundanese\",\"Basa Sunda\"],[\"sv\",\"Swedish\",\"Svenska\"],[\"sw\",\"Swahili\",\"Kiswahili\"],[\"ta\",\"Tamil\",\"தமிழ்\"],[\"te\",\"Telugu\",\"తెలుగు\"],[\"tg\",\"Tajik\",\"тоҷикӣ\"],[\"th\",\"Thai\",\"ไทย\"],[\"ti\",\"Tigrinya\",\"ትግርኛ\"],[\"tk\",\"Turkmen\",\"Türkmen\"],[\"tl\",\"Tagalog\",\"Wikang Tagalog\"],[\"tn\",\"Tswana\",\"Setswana\"],[\"to\",\"Tonga\",\"faka Tonga\"],[\"tr\",\"Turkish\",\"Türkçe\"],[\"ts\",\"Tsonga\",\"Xitsonga\"],[\"tt\",\"Tatar\",\"татар теле\"],[\"tw\",\"Twi\",\"Twi\"],[\"ty\",\"Tahitian\",\"Reo Tahiti\"],[\"ug\",\"Uyghur\",\"ئۇيغۇرچە‎\"],[\"uk\",\"Ukrainian\",\"Українська\"],[\"ur\",\"Urdu\",\"اردو\"],[\"uz\",\"Uzbek\",\"Ўзбек\"],[\"ve\",\"Venda\",\"Tshivenḓa\"],[\"vi\",\"Vietnamese\",\"Tiếng Việt\"],[\"vo\",\"Volapük\",\"Volapük\"],[\"wa\",\"Walloon\",\"walon\"],[\"wo\",\"Wolof\",\"Wollof\"],[\"xh\",\"Xhosa\",\"isiXhosa\"],[\"yi\",\"Yiddish\",\"ייִדיש\"],[\"yo\",\"Yoruba\",\"Yorùbá\"],[\"za\",\"Zhuang\",\"Saɯ cueŋƅ\"],[\"zh\",\"Chinese\",\"中文\"],[\"zu\",\"Zulu\",\"isiZulu\"],[\"ast\",\"Asturian\",\"Asturianu\"],[\"ckb\",\"Sorani (Kurdish)\",\"سۆرانی\"],[\"jbo\",\"Lojban\",\"la .lojban.\"],[\"kab\",\"Kabyle\",\"Taqbaylit\"],[\"kmr\",\"Kurmanji (Kurdish)\",\"Kurmancî\"],[\"ldn\",\"Láadan\",\"Láadan\"],[\"lfn\",\"Lingua Franca Nova\",\"lingua franca nova\"],[\"sco\",\"Scots\",\"Scots\"],[\"tok\",\"Toki Pona\",\"toki pona\"],[\"zba\",\"Balaibalan\",\"باليبلن\"],[\"zgh\",\"Standard Moroccan Tamazight\",\"ⵜⴰⵎⴰⵣⵉⵖⵜ\"]]"; + public static final List allLanguages; + public static final MastodonLanguage ENGLISH = new MastodonLanguage("en", "English", "English"); + + static { + String[][] languages = gson.fromJson(languagesJson, String[][].class); + allLanguages = new ArrayList<>(); + for (String[] language : languages) allLanguages.add(new MastodonLanguage(language[0], language[1], language[2])); + Collections.sort(allLanguages, Comparator.comparing(MastodonLanguage::getDefaultName)); + } + + public final String languageTag, name, englishName; + public final Locale locale; + + private MastodonLanguage(String languageTag, String englishName, String name) { + this.locale = new Locale(languageTag); + this.languageTag = languageTag.toLowerCase(Locale.ROOT); + this.name = name; + this.englishName = englishName; + } + + public String getDefaultName() { + String accordingToLocale = locale.getDisplayLanguage(Locale.getDefault()); + return accordingToLocale.equals(languageTag) ? englishName : accordingToLocale; + } + + public String getLanguageName() { return name; } + + public String getLanguage() { return languageTag; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + return Objects.equals(languageTag, ((MastodonLanguage) o).languageTag); + } + + @Override + public int hashCode() { + return languageTag != null ? languageTag.hashCode() : 0; + } + + public static class LanguageResolver { + private final MastodonLanguage fallbackLanguage; + + public LanguageResolver(Instance instanceInfo) { + String fallbackLanguageTag = !instanceInfo.languages.isEmpty() ? instanceInfo.languages.get(0) : ENGLISH.languageTag; + fallbackLanguage = allLanguages.stream() + .filter(l->l.languageTag.equalsIgnoreCase(fallbackLanguageTag)).findAny() + .orElse(ENGLISH); + } + + public MastodonLanguage from(String language) { + return allLanguages.stream() + .filter(l->l.locale.equals(new Locale(language))).findAny() + .orElse(fallbackLanguage); + } + + public MastodonLanguage getDefault() { + return from(Locale.getDefault().getLanguage()); + } + } +} + diff --git a/mastodon/src/main/res/values/strings.xml b/mastodon/src/main/res/values/strings.xml index b3b3a0ba1..480281b14 100644 --- a/mastodon/src/main/res/values/strings.xml +++ b/mastodon/src/main/res/values/strings.xml @@ -407,6 +407,7 @@ Different people choose different servers for any number of reasons. art.example is a great place for artists, while glasgow.example might be a good pick for Scots.\n\nYou can’t go wrong with any of our recommend servers, so regardless of which one you pick (or if you enter your own in the server search bar), you’ll never miss a beat anywhere. Language: %s All languages + %s (%s) Clear recent languages Are you sure you want to clear your recently used languages? \ No newline at end of file