From 01b7fdd2ad1378c6731cd9446ee3a86a3617a3d7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 28 Mar 2022 11:32:30 +0200 Subject: [PATCH 001/188] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 51b33472..270a36dd 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -32,9 +32,9 @@ "message": "يتعذَّر تعديل الملف التعريفي. يُرجى المُحاولة مرة أُخرى." }, "sign_out": { - "title": "تسجيل الخروج", + "title": "تَسجيلُ الخُروج", "message": "هل أنت متأكد من رغبتك في تسجيل الخُروج؟", - "confirm": "تسجيل الخروج" + "confirm": "تَسجيلُ الخُروج" }, "block_domain": { "title": "هل أنتَ مُتأكِّدٌ حقًا مِن رغبتك في حظر %s بالكامل؟ في معظم الحالات، يكون مِنَ الكافي والمُفَضَّل استهداف عدد محدود للحظر أو الكتم. لن ترى محتوى من هذا النطاق وسوف يُزال جميع متابعيك المتواجدين فيه.", @@ -49,8 +49,8 @@ "message": "هَل أنتَ مُتأكِدٌ مِن رَغبتِكَ فِي حَذفِ هَذَا المَنشُور؟" }, "clean_cache": { - "title": "مَحو ذاكرة التخزين المؤقت", - "message": "تمَّ مَحو %s مِن ذاكرة التخزين المؤقت بنجاح." + "title": "مَحوُ ذاكِرَةِ التَّخزينِ المُؤقَّت", + "message": "مُحِيَ ما مَساحَتُهُ %s مِن ذاكِرَةِ التَّخزينِ المُؤقَّت بِنجاح." } }, "controls": { @@ -79,7 +79,7 @@ "see_more": "عرض المزيد", "preview": "مُعاينة", "share": "المُشارك", - "share_user": "مُشاركة %s", + "share_user": "مُشارَكَةُ %s", "share_post": "مشارك المنشور", "open_in_safari": "الفَتحُ في Safari", "open_in_browser": "الفَتحُ في المُتَصَفِّح", @@ -87,7 +87,7 @@ "manually_search": "البحث يدويًا بدلًا من ذلك", "skip": "تخطي", "reply": "الرَّد", - "report_user": "الإبلاغ عن %s", + "report_user": "الإبلاغُ عَن %s", "block_domain": "حظر %s", "unblock_domain": "رفع الحظر عن %s", "settings": "الإعدادات", @@ -124,7 +124,7 @@ } }, "status": { - "user_reblogged": "أعادَ %s تدوينها", + "user_reblogged": "أعادَ %s تَدوينَها", "user_replied_to": "رَدًا على %s", "show_post": "إظهار منشور", "show_user_profile": "إظهار الملف التعريفي للمُستخدِم", @@ -164,13 +164,13 @@ "request": "إرسال طَلَب", "pending": "قيد المُراجعة", "block": "حظر", - "block_user": "حظر %s", + "block_user": "حَظرُ %s", "block_domain": "حظر %s", "unblock": "رفع الحَظر", "unblock_user": "رفع الحَظر عن %s", "blocked": "محظور", "mute": "كَتم", - "mute_user": "كَتم %s", + "mute_user": "كَتمُ %s", "unmute": "رفع الكتم", "unmute_user": "رفع الكتم عن %s", "muted": "مكتوم", @@ -266,7 +266,7 @@ "checked": "مُتَحَققٌ مِنه", "unchecked": "غيرُ مُتَحَققٍ مِنه" }, - "hint": "يجب أن يكون رمزك السري مكوَّن من ثمان خانات على الأقل" + "hint": "يَجِبُ أن يَحتَوي رَمزُكَ السِرِّيَ علَى ثَمانِ خاناتٍ أقلًا" }, "invite": { "registration_user_invite_request": "لماذا ترغب في الانضمام؟" @@ -380,7 +380,7 @@ "public": "للعامة", "unlisted": "غير مُدرَج", "private": "للمُتابِعينَ فقط", - "direct": "للأشخاص المُشار إليهم فقط" + "direct": "لِمَن أشرتُ إليهِم فَقَط" }, "auto_complete": { "space_to_add": "انقر على مساحة لإضافتِها" @@ -407,7 +407,7 @@ "dashboard": { "posts": "مَنشورات", "following": "مُتابَع", - "followers": "متابِع" + "followers": "مُتابِع" }, "fields": { "add_row": "إضافة صف", @@ -419,7 +419,7 @@ "segmented_control": { "posts": "مَنشورات", "replies": "رُدُود", - "posts_and_replies": "المَنشوراتُ وَالرُدود", + "posts_and_replies": "مَنشُوراتٌ وَرُدُود", "media": "وَسائِط", "about": "حَول" }, @@ -449,9 +449,9 @@ "footer": "لا يُمكِن عَرض المُتابَعات مِنَ الخوادم الأُخرى." }, "search": { - "title": "البحث", + "title": "البَحث", "search_bar": { - "placeholder": "البحث عن وسوم أو مستخدمين", + "placeholder": "اِبحَث عَن وُسُومٍ أو مُستَخدِمين", "cancel": "إلغاء" }, "recommend": { @@ -470,9 +470,9 @@ "searching": { "segment": { "all": "الكُل", - "people": "الأشخاص", - "hashtags": "الوُسُوم", - "posts": "المَنشورات" + "people": "أشخاص", + "hashtags": "وُسُوم", + "posts": "مَنشُورات" }, "empty_state": { "no_results": "لا تُوجَدُ نتائِج" @@ -551,7 +551,7 @@ }, "spicy_zone": { "title": "المنطِقَةُ اللَّاذِعَة", - "clear": "مَحوُ ذاكِرَةُ التَّخزينِ المُؤقت لِلوسائِط", + "clear": "مَحوُ ذاكِرَةِ التَّخزينِ المُؤقَّتِ لِلوسائِط", "signout": "تَسجيلُ الخُروج" } }, From a96d89762599abbab5821a449bfc396af88d7d5b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 28 Mar 2022 12:42:31 +0200 Subject: [PATCH 002/188] New translations app.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/app.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 270a36dd..6b474738 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -61,7 +61,7 @@ "open": "فتح", "add": "إضافة", "remove": "حذف", - "edit": "تحرير", + "edit": "تَحرير", "save": "حفظ", "ok": "حسنًا", "done": "تمّ", @@ -174,7 +174,7 @@ "unmute": "رفع الكتم", "unmute_user": "رفع الكتم عن %s", "muted": "مكتوم", - "edit_info": "تعديل المعلومات" + "edit_info": "تَحريرُ المَعلُومات" }, "timeline": { "filtered": "مُصفَّى", @@ -345,7 +345,7 @@ }, "compose": { "title": { - "new_post": "منشور جديد", + "new_post": "مَنشُورٌ جَديد", "new_reply": "رَدٌّ جديد" }, "media_selection": { @@ -377,7 +377,7 @@ "placeholder": "اكتب تَحذيرًا دَقيقًا هُنا..." }, "visibility": { - "public": "للعامة", + "public": "لِلعَامَّة", "unlisted": "غير مُدرَج", "private": "للمُتابِعينَ فقط", "direct": "لِمَن أشرتُ إليهِم فَقَط" @@ -457,7 +457,7 @@ "recommend": { "button_text": "إظهار الكُل", "hash_tag": { - "title": "ذُو شعبيَّة على ماستودون", + "title": "ذُو شَعبِيَّةٍ عَلَى مَاستودُون", "description": "الوُسُومُ الَّتي تَحظى بقدرٍ كبيرٍ مِنَ الاِهتمام", "people_talking": "%s أشخاص يتحدَّثوا" }, From c5fe5a872c7bbe4e4dad7c560a7c7579e0c8ad10 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 28 Mar 2022 12:42:32 +0200 Subject: [PATCH 003/188] New translations ios-infoPlist.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json b/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json index 22fb2868..1535679c 100644 --- a/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json +++ b/Localization/StringsConvertor/input/ar_SA/ios-infoPlist.json @@ -1,6 +1,6 @@ { "NSCameraUsageDescription": "يُستخدم لالتقاط الصورة عِندَ نشر الحالات", "NSPhotoLibraryAddUsageDescription": "يُستخدم لحِفظ الصورة في مكتبة الصور", - "NewPostShortcutItemTitle": "منشور جديد", + "NewPostShortcutItemTitle": "مَنشُورٌ جَديد", "SearchShortcutItemTitle": "البحث" } From 0fa16863599441262bec6683c455bceba741342e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 28 Mar 2022 12:42:33 +0200 Subject: [PATCH 004/188] New translations Intents.strings (Arabic) --- .../StringsConvertor/Intents/input/ar_SA/Intents.strings | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings index cde27dc9..49183a43 100644 --- a/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/ar_SA/Intents.strings @@ -1,4 +1,4 @@ -"16wxgf" = "النَشر على ماستودون"; +"16wxgf" = "النَّشرُ عَلَى مَاستودُون"; "751xkl" = "محتوى نصي"; @@ -14,7 +14,7 @@ "RxSqsb" = "مَنشور"; -"WCIR3D" = "نَشر ${content} على ماستودون"; +"WCIR3D" = "نَشرُ ${content} عَلَى مَاستودُون"; "ZKJSNu" = "مَنشور"; @@ -32,9 +32,9 @@ "ayoYEb-ehFLjY" = "${content}، المُتابِعُون فقط"; -"dUyuGg" = "النشر على ماستدون"; +"dUyuGg" = "النَّشرُ عَلَى مَاستودُون"; -"dYQ5NN" = "للعامة"; +"dYQ5NN" = "لِلعَامَّة"; "ehFLjY" = "لمتابعيك فقط"; From 6076d76d4fb1abbaf103096258a07db96d1fb957 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 29 Mar 2022 16:27:10 +0200 Subject: [PATCH 005/188] New translations app.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/app.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 6b474738..f5873444 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -148,7 +148,7 @@ "mention": "إشارة", "link": "رابط", "hashtag": "وسم", - "email": "بريد إلكتروني", + "email": "بَريدٌ إلِكتُرُونِيّ", "emoji": "رمز تعبيري" }, "visibility": { @@ -249,14 +249,14 @@ "delete": "حذف" }, "username": { - "placeholder": "اِسم مُستَخدِم", + "placeholder": "اِسمُ مُستَخدِم", "duplicate_prompt": "اِسم المُستَخدِم هذا مأخوذٌ بالفعل." }, "display_name": { - "placeholder": "اِسم العَرض" + "placeholder": "اِسمُ عَرض" }, "email": { - "placeholder": "بريد إلكتروني" + "placeholder": "بَريدٌ إلِكتُرُونِيّ" }, "password": { "placeholder": "رمز سري", @@ -274,7 +274,7 @@ }, "error": { "item": { - "username": "اِسم المُستَخدِم", + "username": "اِسمُ المُستَخدِم", "email": "البريد الإلكتروني", "password": "الرمز السري", "agreement": "الاِتِّفاقيَّة", From 34cadfa8a9590a6758b433a9404f32fff72fba47 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 29 Mar 2022 17:38:38 +0200 Subject: [PATCH 006/188] New translations app.json (Hindi) --- Localization/StringsConvertor/input/hi_IN/app.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/hi_IN/app.json b/Localization/StringsConvertor/input/hi_IN/app.json index ad99e178..9a172fad 100644 --- a/Localization/StringsConvertor/input/hi_IN/app.json +++ b/Localization/StringsConvertor/input/hi_IN/app.json @@ -2,8 +2,8 @@ "common": { "alerts": { "common": { - "please_try_again": "Please try again.", - "please_try_again_later": "Please try again later." + "please_try_again": "कृपया फिर से प्रयास करें।", + "please_try_again_later": "बाद में फिर से प्रयास करें।" }, "sign_up_failure": { "title": "Sign Up Failure" From 3f729179ad281379e626dbba6b519711c5643909 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 29 Mar 2022 18:39:47 +0200 Subject: [PATCH 007/188] New translations app.json (Hindi) --- Localization/StringsConvertor/input/hi_IN/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/hi_IN/app.json b/Localization/StringsConvertor/input/hi_IN/app.json index 9a172fad..82c9661b 100644 --- a/Localization/StringsConvertor/input/hi_IN/app.json +++ b/Localization/StringsConvertor/input/hi_IN/app.json @@ -45,7 +45,7 @@ "message": "Please enable the photo library access permission to save the photo." }, "delete_post": { - "title": "Delete Post", + "title": "पोस्ट को हटाएं", "message": "Are you sure you want to delete this post?" }, "clean_cache": { From 1a5299e8344e2ca131aedd429f772e118c834f58 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:37 +0200 Subject: [PATCH 008/188] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 5d1d70fb..582ff144 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Profîla bikarhêner nîşan bide", "content_warning": "Hişyariya naverokê", "media_content_warning": "Ji bo eşkerekirinê li derekî bitikîne", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Deng bide", "closed": "Girtî" @@ -141,7 +142,11 @@ "favorite": "Bijarte", "unfavorite": "Nebijarte", "menu": "Kulîn", - "hide": "Veşêre" + "hide": "Veşêre", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Astengiyê li ser ajimêr rake", "message": "Ji bo rakirina astengkirinê %s bipejirîne" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Moda tarî ya reş a rastîn", "disable_avatar_animation": "Avatarên anîmasyonî neçalak bike", "disable_emoji_animation": "Emojiyên anîmasyonî neçalak bike", - "using_default_browser": "Ji bo vekirina girêdanan geroka berdest bi kar bîne" + "using_default_browser": "Ji bo vekirina girêdanan geroka berdest bi kar bîne", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "Devera acizker", From 53939ad404eee360261d379f14891ab3b79af1b9 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:38 +0200 Subject: [PATCH 009/188] New translations Localizable.stringsdict (English) --- .../input/en_US/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/en_US/Localizable.stringsdict b/Localization/StringsConvertor/input/en_US/Localizable.stringsdict index 730e2902..503ff9db 100644 --- a/Localization/StringsConvertor/input/en_US/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/en_US/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From bd09097f7727ae926463fbdc869838f2a1c17d14 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:39 +0200 Subject: [PATCH 010/188] New translations app.json (Russian) --- .../StringsConvertor/input/ru_RU/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/ru_RU/app.json b/Localization/StringsConvertor/input/ru_RU/app.json index 58cedfc7..0309c463 100644 --- a/Localization/StringsConvertor/input/ru_RU/app.json +++ b/Localization/StringsConvertor/input/ru_RU/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Показать профиль пользователя", "content_warning": "Предупреждение о содержании", "media_content_warning": "Нажмите в любом месте, чтобы показать", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Проголосовать", "closed": "Завершён" @@ -141,7 +142,11 @@ "favorite": "Добавить в избранное", "unfavorite": "Убрать из избранного", "menu": "Меню", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "Ссылка", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Полноценно чёрный режим", "disable_avatar_animation": "Отключить анимацию аватарок", "disable_emoji_animation": "Отключить анимацию эмодзи", - "using_default_browser": "Использовать браузер по умолчанию для открытия ссылок" + "using_default_browser": "Использовать браузер по умолчанию для открытия ссылок", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "Зона скукотищи", From d0c7f1ee92c1dc004e663ade7a02153b62e4a1c3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:40 +0200 Subject: [PATCH 011/188] New translations Localizable.stringsdict (Russian) --- .../input/ru_RU/Localizable.stringsdict | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict index 96afce4e..626a10d7 100644 --- a/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ru_RU/Localizable.stringsdict @@ -142,6 +142,26 @@ %ld продвинули + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + few + %ld replies + many + %ld replies + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From dcb9df42412fd78d7cb16e1ab884ca38d20a7170 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:42 +0200 Subject: [PATCH 012/188] New translations app.json (Swedish) --- .../StringsConvertor/input/sv_SE/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/sv_SE/app.json b/Localization/StringsConvertor/input/sv_SE/app.json index 59ad0d6e..d21203af 100644 --- a/Localization/StringsConvertor/input/sv_SE/app.json +++ b/Localization/StringsConvertor/input/sv_SE/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Show user profile", "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vote", "closed": "Closed" @@ -141,7 +142,11 @@ "favorite": "Favorite", "unfavorite": "Unfavorite", "menu": "Meny", - "hide": "Dölj" + "hide": "Dölj", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Inaktivera animerade avatarer", "disable_emoji_animation": "Inaktivera animerade emojis", - "using_default_browser": "Use default browser to open links" + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "The Boring Zone", From 90bb05d93bb12a3f1a1e5e4ce17d587f9064bc34 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:42 +0200 Subject: [PATCH 013/188] New translations Localizable.stringsdict (Swedish) --- .../input/sv_SE/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict b/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict index f8da5e39..50eab95b 100644 --- a/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/sv_SE/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From e6ab06b4966291c123e03b42019fb4bb243e3c51 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:43 +0200 Subject: [PATCH 014/188] New translations app.json (Chinese Simplified) --- .../StringsConvertor/input/zh_CN/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/zh_CN/app.json b/Localization/StringsConvertor/input/zh_CN/app.json index 74ea0529..e0b3e084 100644 --- a/Localization/StringsConvertor/input/zh_CN/app.json +++ b/Localization/StringsConvertor/input/zh_CN/app.json @@ -130,6 +130,7 @@ "show_user_profile": "查看用户个人资料", "content_warning": "内容警告", "media_content_warning": "点击任意位置显示", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "投票", "closed": "已关闭" @@ -141,7 +142,11 @@ "favorite": "喜欢", "unfavorite": "取消喜欢", "menu": "菜单", - "hide": "隐藏" + "hide": "隐藏", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "解除屏蔽帐户", "message": "确认取消屏蔽 %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "纯黑模式", "disable_avatar_animation": "禁用动画头像", "disable_emoji_animation": "禁用动画表情", - "using_default_browser": "使用默认浏览器打开链接" + "using_default_browser": "使用默认浏览器打开链接", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "The Boring Zone", From fe8df6abfade08c99e7d2f32762a2d2dc10f2a58 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:44 +0200 Subject: [PATCH 015/188] New translations Localizable.stringsdict (Chinese Simplified) --- .../input/zh_CN/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict index 12b8b5f6..41890383 100644 --- a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict @@ -100,6 +100,20 @@ %ld 条转发 + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 7716c944fb70a346d16ed6f407a45cf11db484e7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:45 +0200 Subject: [PATCH 016/188] New translations app.json (Chinese Traditional) --- .../StringsConvertor/input/zh_TW/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/zh_TW/app.json b/Localization/StringsConvertor/input/zh_TW/app.json index be2442e4..e1e61323 100644 --- a/Localization/StringsConvertor/input/zh_TW/app.json +++ b/Localization/StringsConvertor/input/zh_TW/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Show user profile", "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "投票", "closed": "Closed" @@ -141,7 +142,11 @@ "favorite": "Favorite", "unfavorite": "Unfavorite", "menu": "Menu", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Disable animated avatars", "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links" + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "The Boring Zone", From a9eb42a598d292a44ce57ab1cc4db3f9b9c35ad1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:48 +0200 Subject: [PATCH 017/188] New translations Localizable.stringsdict (Chinese Traditional) --- .../input/zh_TW/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict b/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict index dafab129..c69fd562 100644 --- a/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/zh_TW/Localizable.stringsdict @@ -100,6 +100,20 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 7949f9dc90f0d3560074fefdcb1a2d3e031fe76c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:49 +0200 Subject: [PATCH 018/188] New translations app.json (English) --- .../StringsConvertor/input/en_US/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/en_US/app.json b/Localization/StringsConvertor/input/en_US/app.json index ad99e178..f0dc0ebf 100644 --- a/Localization/StringsConvertor/input/en_US/app.json +++ b/Localization/StringsConvertor/input/en_US/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Show user profile", "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vote", "closed": "Closed" @@ -141,7 +142,11 @@ "favorite": "Favorite", "unfavorite": "Unfavorite", "menu": "Menu", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Disable animated avatars", "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links" + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "The Boring Zone", From b78733990e86b51b339b7a88c734db2628b53fff Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:50 +0200 Subject: [PATCH 019/188] New translations app.json (Portuguese, Brazilian) --- .../StringsConvertor/input/pt_BR/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/pt_BR/app.json b/Localization/StringsConvertor/input/pt_BR/app.json index ad99e178..f0dc0ebf 100644 --- a/Localization/StringsConvertor/input/pt_BR/app.json +++ b/Localization/StringsConvertor/input/pt_BR/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Show user profile", "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vote", "closed": "Closed" @@ -141,7 +142,11 @@ "favorite": "Favorite", "unfavorite": "Unfavorite", "menu": "Menu", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Disable animated avatars", "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links" + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "The Boring Zone", From 86f48c4b88116e968979bbdfe5d271aeefcb15e5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:51 +0200 Subject: [PATCH 020/188] New translations app.json (Portuguese) --- .../StringsConvertor/input/pt_PT/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/pt_PT/app.json b/Localization/StringsConvertor/input/pt_PT/app.json index ad99e178..f0dc0ebf 100644 --- a/Localization/StringsConvertor/input/pt_PT/app.json +++ b/Localization/StringsConvertor/input/pt_PT/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Show user profile", "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vote", "closed": "Closed" @@ -141,7 +142,11 @@ "favorite": "Favorite", "unfavorite": "Unfavorite", "menu": "Menu", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Disable animated avatars", "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links" + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "The Boring Zone", From 8e52a607de718aa125c87b81e525d7f3035c7bd2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:52 +0200 Subject: [PATCH 021/188] New translations Localizable.stringsdict (Portuguese, Brazilian) --- .../input/pt_BR/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict b/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict index 730e2902..503ff9db 100644 --- a/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/pt_BR/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From f3bab6b01c24d311a3a0efcd5f9a754cf5f4926e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:53 +0200 Subject: [PATCH 022/188] New translations app.json (Indonesian) --- .../StringsConvertor/input/id_ID/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/id_ID/app.json b/Localization/StringsConvertor/input/id_ID/app.json index c6af04e0..1de960d1 100644 --- a/Localization/StringsConvertor/input/id_ID/app.json +++ b/Localization/StringsConvertor/input/id_ID/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Tampilkan Profil Pengguna", "content_warning": "Peringatan Konten", "media_content_warning": "Ketuk di mana saja untuk melihat", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vote", "closed": "Ditutup" @@ -141,7 +142,11 @@ "favorite": "Favorit", "unfavorite": "Unfavorite", "menu": "Menu", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Disable animated avatars", "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links" + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "Zona Membosankan", From 5bc00f84adc6d498578359c82d1c59548f4982e7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:54 +0200 Subject: [PATCH 023/188] New translations Localizable.stringsdict (Indonesian) --- .../input/id_ID/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict b/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict index 88c0fac9..a4a0f493 100644 --- a/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/id_ID/Localizable.stringsdict @@ -100,6 +100,20 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 01362f4f7d62fa4d9402f36e8b6c7d9873a91155 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:55 +0200 Subject: [PATCH 024/188] New translations app.json (Spanish, Argentina) --- .../StringsConvertor/input/es_AR/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/es_AR/app.json b/Localization/StringsConvertor/input/es_AR/app.json index 106ffb64..ab0517da 100644 --- a/Localization/StringsConvertor/input/es_AR/app.json +++ b/Localization/StringsConvertor/input/es_AR/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Mostrar perfil de usuario", "content_warning": "Advertencia de contenido", "media_content_warning": "Toca en cualquier lugar para mostrar", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Votar", "closed": "Cerrada" @@ -141,7 +142,11 @@ "favorite": "Marcar como favorito", "unfavorite": "Dejar de marcar como favorito", "menu": "Menú", - "hide": "Ocultar" + "hide": "Ocultar", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "Dirección web", @@ -440,6 +445,12 @@ "title": "Desbloquear cuenta", "message": "Confirmá para desbloquear a %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Modo negro oscuro real", "disable_avatar_animation": "Deshabilitar avatares animados", "disable_emoji_animation": "Deshabilitar emojis animados", - "using_default_browser": "Usar navegador web predeterminado para abrir enlaces" + "using_default_browser": "Usar navegador web predeterminado para abrir enlaces", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "La zona aburrida", From 5b05803c8970c111ad4a2a9e8fc1693455450816 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:56 +0200 Subject: [PATCH 025/188] New translations Localizable.stringsdict (Spanish, Argentina) --- .../input/es_AR/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict index f4f0097e..c63073f4 100644 --- a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld adhesiones + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 7c5bcab840135cb01387d7060d97b470382b0843 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:57 +0200 Subject: [PATCH 026/188] New translations app.json (Thai) --- .../StringsConvertor/input/th_TH/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index 001075b1..183f9cfc 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -130,6 +130,7 @@ "show_user_profile": "แสดงโปรไฟล์ผู้ใช้", "content_warning": "คำเตือนเนื้อหา", "media_content_warning": "แตะที่ใดก็ตามเพื่อเปิดเผย", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "ลงคะแนน", "closed": "ปิดแล้ว" @@ -141,7 +142,11 @@ "favorite": "ชื่นชอบ", "unfavorite": "เลิกชื่นชอบ", "menu": "เมนู", - "hide": "ซ่อน" + "hide": "ซ่อน", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "เลิกปิดกั้นบัญชี", "message": "ยืนยันเพื่อเลิกปิดกั้น %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "โหมดมืดดำสนิท", "disable_avatar_animation": "ปิดใช้งานภาพประจำตัวแบบเคลื่อนไหว", "disable_emoji_animation": "ปิดใช้งานอีโมจิแบบเคลื่อนไหว", - "using_default_browser": "ใช้เบราว์เซอร์เริ่มต้นเพื่อเปิดลิงก์" + "using_default_browser": "ใช้เบราว์เซอร์เริ่มต้นเพื่อเปิดลิงก์", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "โซนน่าเบื่อ", From 60cb69ff4d2feb195713985bdbc7447c698074b0 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:58 +0200 Subject: [PATCH 027/188] New translations Localizable.stringsdict (Thai) --- .../input/th_TH/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict index 8971821f..3895c399 100644 --- a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict @@ -100,6 +100,20 @@ %ld การดัน + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 5e62916e0564f8cac68581d306efe4806e5f7c62 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:54:59 +0200 Subject: [PATCH 028/188] New translations Localizable.stringsdict (Hindi) --- .../input/hi_IN/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict b/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict index 730e2902..503ff9db 100644 --- a/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/hi_IN/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 8b5864c66167fc33e7413d602dbf8fc213bd85cf Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:02 +0200 Subject: [PATCH 029/188] New translations Localizable.stringsdict (Portuguese) --- .../input/pt_PT/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict b/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict index 730e2902..503ff9db 100644 --- a/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/pt_PT/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From f240308b4fdf248f3691cfe998279ef1bc40ff85 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:03 +0200 Subject: [PATCH 030/188] New translations Localizable.stringsdict (Dutch) --- .../input/nl_NL/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict b/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict index 8b6ab05c..5ae33cbe 100644 --- a/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/nl_NL/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld gedeelde berichten + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 2068a9006d5161df2ed647174843d99c9de07de1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:04 +0200 Subject: [PATCH 031/188] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index f5873444..23d309d2 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -130,6 +130,7 @@ "show_user_profile": "إظهار الملف التعريفي للمُستخدِم", "content_warning": "تحذير المُحتوى", "media_content_warning": "انقر للكشف", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "صَوِّت", "closed": "انتهى" @@ -141,7 +142,11 @@ "favorite": "التفضيل", "unfavorite": "إزالة التفضيل", "menu": "القائمة", - "hide": "إخفاء" + "hide": "إخفاء", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "عنوان URL", @@ -440,6 +445,12 @@ "title": "رَفعُ الحَظرِ عَنِ الحِساب", "message": "تأكيدُ رَفع الحَظرِ عَن %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "النَّمَطُ الأسوَدُ الداكِنُ الحَقيقي", "disable_avatar_animation": "تَعطيلُ الصوَرِ الرمزيَّةِ المُتحرِّكَة", "disable_emoji_animation": "تَعطيلُ الرُموزِ التَّعبيريَّةِ المُتحرِّكَة", - "using_default_browser": "اِستِخدامُ المُتصفِّحِ الاِفتراضي لِفتحِ الرَّوابِط" + "using_default_browser": "اِستِخدامُ المُتصفِّحِ الاِفتراضي لِفتحِ الرَّوابِط", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "المنطِقَةُ المُملَّة", From 27027489fab855f9c2aa3022c8aaba4859a0a2e4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:05 +0200 Subject: [PATCH 032/188] New translations app.json (Danish) --- .../StringsConvertor/input/da_DK/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/da_DK/app.json b/Localization/StringsConvertor/input/da_DK/app.json index ad99e178..f0dc0ebf 100644 --- a/Localization/StringsConvertor/input/da_DK/app.json +++ b/Localization/StringsConvertor/input/da_DK/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Show user profile", "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vote", "closed": "Closed" @@ -141,7 +142,11 @@ "favorite": "Favorite", "unfavorite": "Unfavorite", "menu": "Menu", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Disable animated avatars", "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links" + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "The Boring Zone", From eb0412a500d7d2ce520405717386dd194c3f50e9 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:06 +0200 Subject: [PATCH 033/188] New translations app.json (Hindi) --- .../StringsConvertor/input/hi_IN/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/hi_IN/app.json b/Localization/StringsConvertor/input/hi_IN/app.json index 82c9661b..a33a4f62 100644 --- a/Localization/StringsConvertor/input/hi_IN/app.json +++ b/Localization/StringsConvertor/input/hi_IN/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Show user profile", "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vote", "closed": "Closed" @@ -141,7 +142,11 @@ "favorite": "Favorite", "unfavorite": "Unfavorite", "menu": "Menu", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Disable animated avatars", "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links" + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "The Boring Zone", From fafd33b234b64f973764ee46de6edc222927a96f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:07 +0200 Subject: [PATCH 034/188] New translations app.json (Romanian) --- .../StringsConvertor/input/ro_RO/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/ro_RO/app.json b/Localization/StringsConvertor/input/ro_RO/app.json index b9ef116d..eeb4dc86 100644 --- a/Localization/StringsConvertor/input/ro_RO/app.json +++ b/Localization/StringsConvertor/input/ro_RO/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Show user profile", "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vote", "closed": "Closed" @@ -141,7 +142,11 @@ "favorite": "Favorite", "unfavorite": "Unfavorite", "menu": "Menu", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Disable animated avatars", "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links" + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "The Boring Zone", From 56aed2f45225b6944deb4b860c13715a83d5265e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:08 +0200 Subject: [PATCH 035/188] New translations Localizable.stringsdict (Romanian) --- .../input/ro_RO/Localizable.stringsdict | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict b/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict index 8cda4bbd..2acc3276 100644 --- a/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ro_RO/Localizable.stringsdict @@ -128,6 +128,24 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + few + %ld replies + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From a24b73261c8f42b9e457091f788c0d5583241811 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:09 +0200 Subject: [PATCH 036/188] New translations app.json (French) --- .../StringsConvertor/input/fr_FR/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/fr_FR/app.json b/Localization/StringsConvertor/input/fr_FR/app.json index 9941ff99..248253e9 100644 --- a/Localization/StringsConvertor/input/fr_FR/app.json +++ b/Localization/StringsConvertor/input/fr_FR/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Montrer le profil de l’utilisateur·rice", "content_warning": "Avertissement de contenu", "media_content_warning": "Tapotez n’importe où pour révéler la publication", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Voter", "closed": "Fermé" @@ -141,7 +142,11 @@ "favorite": "Favori", "unfavorite": "Retirer des favoris", "menu": "Menu", - "hide": "Cacher" + "hide": "Cacher", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Débloquer le compte", "message": "Confirmer le déblocage de %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Vrai mode sombre", "disable_avatar_animation": "Désactiver les avatars animés", "disable_emoji_animation": "Désactiver les émojis animées", - "using_default_browser": "Utiliser le navigateur par défaut pour ouvrir les liens" + "using_default_browser": "Utiliser le navigateur par défaut pour ouvrir les liens", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "La zone ennuyante", From c44de2ba86d7771d32adcd46a6b206a88a7351a4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:11 +0200 Subject: [PATCH 037/188] New translations Localizable.stringsdict (French) --- .../input/fr_FR/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict index 37f07e67..93ee696f 100644 --- a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 18b0bbc54bd6050f187b586fb3905fab8aee1767 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:11 +0200 Subject: [PATCH 038/188] New translations app.json (Spanish) --- .../StringsConvertor/input/es_ES/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/es_ES/app.json b/Localization/StringsConvertor/input/es_ES/app.json index cfebae26..e9f352cb 100644 --- a/Localization/StringsConvertor/input/es_ES/app.json +++ b/Localization/StringsConvertor/input/es_ES/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Mostrar perfil del usuario", "content_warning": "Advertencia de Contenido", "media_content_warning": "Pulsa en cualquier sitio para mostrar", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vota", "closed": "Cerrado" @@ -141,7 +142,11 @@ "favorite": "Favorito", "unfavorite": "No favorito", "menu": "Menú", - "hide": "Ocultar" + "hide": "Ocultar", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Desbloquear cuenta", "message": "Confirmar para desbloquear a %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Modo oscuro negro real", "disable_avatar_animation": "Deshabilitar avatares animados", "disable_emoji_animation": "Deshabilitar emojis animados", - "using_default_browser": "Usar navegador predeterminado para abrir los enlaces" + "using_default_browser": "Usar navegador predeterminado para abrir los enlaces", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "La Zona Aburrida", From 406f2b7e74ba8ccbfcbbdf7a2812cfc8dc969c8d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:12 +0200 Subject: [PATCH 039/188] New translations Localizable.stringsdict (Spanish) --- .../input/es_ES/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict index 186218af..24e407d0 100644 --- a/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_ES/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogueos + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 7a5a12119696066cabcff57555d4327805bfe1a3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:13 +0200 Subject: [PATCH 040/188] New translations Localizable.stringsdict (Arabic) --- .../input/ar_SA/Localizable.stringsdict | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index 0b28c577..4ecfe591 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -170,6 +170,30 @@ %ld إعادة تدوين + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + zero + %ld replies + one + 1 reply + two + %ld replies + few + %ld replies + many + %ld replies + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 5afd4ce6fcc0bfbc628b516126e80884699e908a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:15 +0200 Subject: [PATCH 041/188] New translations app.json (Catalan) --- .../StringsConvertor/input/ca_ES/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index c3aac1e5..d7008bff 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Mostra el perfil de l'usuari", "content_warning": "Advertència de Contingut", "media_content_warning": "Toca qualsevol lloc per mostrar", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vota", "closed": "Finalitzada" @@ -141,7 +142,11 @@ "favorite": "Favorit", "unfavorite": "Desfer Favorit", "menu": "Menú", - "hide": "Amaga" + "hide": "Amaga", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Desbloqueja el Compte", "message": "Confirma per a desbloquejar %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Mode negre fosc autèntic", "disable_avatar_animation": "Desactiva avatars animats", "disable_emoji_animation": "Desactiva emojis animats", - "using_default_browser": "Utilitza el navegador predeterminat per a obrir enllaços" + "using_default_browser": "Utilitza el navegador predeterminat per a obrir enllaços", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "La Zona Avorrida", From f66ae58e997803ccd2f1400d9bca60678dbf00fd Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:16 +0200 Subject: [PATCH 042/188] New translations Localizable.stringsdict (Catalan) --- .../input/ca_ES/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict index 140185ba..9475b3e2 100644 --- a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld impulsos + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 0392d4378cb813bd5c8b7b311cd7d1888a7aa45c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:17 +0200 Subject: [PATCH 043/188] New translations Localizable.stringsdict (Danish) --- .../input/da_DK/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict b/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict index 730e2902..503ff9db 100644 --- a/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/da_DK/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From d2cd365236dc606639029634371899b27c343b61 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:18 +0200 Subject: [PATCH 044/188] New translations app.json (Dutch) --- .../StringsConvertor/input/nl_NL/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/nl_NL/app.json b/Localization/StringsConvertor/input/nl_NL/app.json index ae8f2d2d..6d004c55 100644 --- a/Localization/StringsConvertor/input/nl_NL/app.json +++ b/Localization/StringsConvertor/input/nl_NL/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Toon Gebruikersprofiel", "content_warning": "Inhoudswaarschuwing", "media_content_warning": "Tap hier om te tonen", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Stemmen", "closed": "Gesloten" @@ -141,7 +142,11 @@ "favorite": "Toevoegen aan Favorieten", "unfavorite": "Verwijderen uit Favorieten", "menu": "Menu", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Echt zwarte donker uiterlijk", "disable_avatar_animation": "Geanimeerde avatars uitschakelen", "disable_emoji_animation": "Geanimeerde emojis uitschakelen", - "using_default_browser": "Gebruik de standaard browser om links te openen" + "using_default_browser": "Gebruik de standaard browser om links te openen", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "De Saaie Instellingen", From a1b4682ec87e72f48bd74b7b2dfd69c7710c130e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:19 +0200 Subject: [PATCH 045/188] New translations app.json (German) --- .../StringsConvertor/input/de_DE/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/de_DE/app.json b/Localization/StringsConvertor/input/de_DE/app.json index f62f9f95..e3601595 100644 --- a/Localization/StringsConvertor/input/de_DE/app.json +++ b/Localization/StringsConvertor/input/de_DE/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Benutzerprofil anzeigen", "content_warning": "Inhaltswarnung", "media_content_warning": "Tippe irgendwo zum Anzeigen", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Abstimmen", "closed": "Beendet" @@ -141,7 +142,11 @@ "favorite": "Favorit", "unfavorite": "Aus Favoriten entfernen", "menu": "Menü", - "hide": "Verstecken" + "hide": "Verstecken", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Konto entsperren", "message": "Bestätige %s zu entsperren" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Vollständig dunkler Dunkelmodus", "disable_avatar_animation": "Animierte Profilbilder deaktivieren", "disable_emoji_animation": "Animierte Emojis deaktivieren", - "using_default_browser": "Standardbrowser zum Öffnen von Links verwenden" + "using_default_browser": "Standardbrowser zum Öffnen von Links verwenden", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "Der langweilige Bereich", From fc918b8884c7f4aa8b36df6d55136a4885200369 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:21 +0200 Subject: [PATCH 046/188] New translations Localizable.stringsdict (German) --- .../input/de_DE/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict index 66b7f2a2..cd721862 100644 --- a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld Reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From d32e3c4e78410da73d7700d151114723ec82d9fa Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:22 +0200 Subject: [PATCH 047/188] New translations app.json (Basque) --- .../StringsConvertor/input/eu_ES/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/eu_ES/app.json b/Localization/StringsConvertor/input/eu_ES/app.json index 39d06227..ff249acd 100644 --- a/Localization/StringsConvertor/input/eu_ES/app.json +++ b/Localization/StringsConvertor/input/eu_ES/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Erakutsi erabiltzailearen profila", "content_warning": "Edukiaren abisua", "media_content_warning": "Ukitu edonon bistaratzeko", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Bozkatu", "closed": "Itxita" @@ -141,7 +142,11 @@ "favorite": "Gogokoa", "unfavorite": "Kendu gogokoa", "menu": "Menua", - "hide": "Ezkutatu" + "hide": "Ezkutatu", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URLa", @@ -440,6 +445,12 @@ "title": "Desblokeatu kontua", "message": "Berretsi %s desblokeatzea" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Benetako modu beltz iluna", "disable_avatar_animation": "Desgaitu abatar animatuak", "disable_emoji_animation": "Desgaitu emoji animatuak", - "using_default_browser": "Erabili nabigatzaile lehenetsia estekak irekitzeko" + "using_default_browser": "Erabili nabigatzaile lehenetsia estekak irekitzeko", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "Eremu aspergarria", From 37baaf240a9357908ddab499b527bd5122555507 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:23 +0200 Subject: [PATCH 048/188] New translations Localizable.stringsdict (Basque) --- .../input/eu_ES/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/eu_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/eu_ES/Localizable.stringsdict index 817e8372..2069e27a 100644 --- a/Localization/StringsConvertor/input/eu_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/eu_ES/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld bultzada + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 2fc2bc67acb5fe3cd21232b1e750124f14f48225 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:26 +0200 Subject: [PATCH 049/188] New translations app.json (Italian) --- .../StringsConvertor/input/it_IT/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/app.json b/Localization/StringsConvertor/input/it_IT/app.json index ad99e178..f0dc0ebf 100644 --- a/Localization/StringsConvertor/input/it_IT/app.json +++ b/Localization/StringsConvertor/input/it_IT/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Show user profile", "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vote", "closed": "Closed" @@ -141,7 +142,11 @@ "favorite": "Favorite", "unfavorite": "Unfavorite", "menu": "Menu", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Disable animated avatars", "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links" + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "The Boring Zone", From 6d2a4d203d629024d195de90449104dee52121ab Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:27 +0200 Subject: [PATCH 050/188] New translations Localizable.stringsdict (Italian) --- .../input/it_IT/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict b/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict index 730e2902..503ff9db 100644 --- a/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From b218381cf7f760a7c3fe247a4229c844ad01db80 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:28 +0200 Subject: [PATCH 051/188] New translations app.json (Japanese) --- .../StringsConvertor/input/ja_JP/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/ja_JP/app.json b/Localization/StringsConvertor/input/ja_JP/app.json index 7ddfa51c..5117c19f 100644 --- a/Localization/StringsConvertor/input/ja_JP/app.json +++ b/Localization/StringsConvertor/input/ja_JP/app.json @@ -130,6 +130,7 @@ "show_user_profile": "プロフィールを見る", "content_warning": "コンテンツ警告", "media_content_warning": "どこかをタップして表示", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "投票", "closed": "クローズド" @@ -141,7 +142,11 @@ "favorite": "お気に入り", "unfavorite": "お気に入り登録を取り消す", "menu": "メニュー", - "hide": "非表示" + "hide": "非表示", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "真っ黒なダークテーマを使用する", "disable_avatar_animation": "アバターのアニメーションを無効化する", "disable_emoji_animation": "絵文字のアニメーションを無効化する", - "using_default_browser": "既定のブラウザでリンクを開く" + "using_default_browser": "既定のブラウザでリンクを開く", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "アプリについて", From 11f263da5eb87c2559309316e8a0568c2810c708 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:29 +0200 Subject: [PATCH 052/188] New translations Localizable.stringsdict (Japanese) --- .../input/ja_JP/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict b/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict index f1c5e6e2..8dfc9507 100644 --- a/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ja_JP/Localizable.stringsdict @@ -100,6 +100,20 @@ %ld ブースト + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From fee0fed17a1d86a3638b6fa944c383d6bcb33d2e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:30 +0200 Subject: [PATCH 053/188] New translations app.json (Korean) --- .../StringsConvertor/input/ko_KR/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/ko_KR/app.json b/Localization/StringsConvertor/input/ko_KR/app.json index 3f9f4c19..e75a2ae0 100644 --- a/Localization/StringsConvertor/input/ko_KR/app.json +++ b/Localization/StringsConvertor/input/ko_KR/app.json @@ -130,6 +130,7 @@ "show_user_profile": "사용자 프로필 보기", "content_warning": "열람 주의", "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "투표", "closed": "마감" @@ -141,7 +142,11 @@ "favorite": "즐겨찾기", "unfavorite": "즐겨찾기 해제", "menu": "메뉴", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "트루 블랙 어두운 모드", "disable_avatar_animation": "움직이는 아바타 비활성화", "disable_emoji_animation": "움직이는 에모지 비활성화", - "using_default_browser": "기본 브라우저로 링크 열기" + "using_default_browser": "기본 브라우저로 링크 열기", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "지루한 영역", From 25092d0e6082617381caaff50e65e21f20813965 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:32 +0200 Subject: [PATCH 054/188] New translations Localizable.stringsdict (Korean) --- .../input/ko_KR/Localizable.stringsdict | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict b/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict index 7c990671..2af4c9ce 100644 --- a/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ko_KR/Localizable.stringsdict @@ -100,6 +100,20 @@ %ld 개의 리블로그 + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 4eeb6cb8b3321820846ceedf1348df310c4d6b73 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:33 +0200 Subject: [PATCH 055/188] New translations app.json (Welsh) --- .../StringsConvertor/input/cy_GB/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/cy_GB/app.json b/Localization/StringsConvertor/input/cy_GB/app.json index ad99e178..f0dc0ebf 100644 --- a/Localization/StringsConvertor/input/cy_GB/app.json +++ b/Localization/StringsConvertor/input/cy_GB/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Show user profile", "content_warning": "Content Warning", "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vote", "closed": "Closed" @@ -141,7 +142,11 @@ "favorite": "Favorite", "unfavorite": "Unfavorite", "menu": "Menu", - "hide": "Hide" + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "True black dark mode", "disable_avatar_animation": "Disable animated avatars", "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links" + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "The Boring Zone", From ac8f97875dbc3f3f38761419b9a32242615b0546 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:34 +0200 Subject: [PATCH 056/188] New translations Localizable.stringsdict (Welsh) --- .../input/cy_GB/Localizable.stringsdict | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict b/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict index e6b0d5f9..e0f1e0f2 100644 --- a/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/cy_GB/Localizable.stringsdict @@ -170,6 +170,30 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + zero + %ld replies + one + 1 reply + two + %ld replies + few + %ld replies + many + %ld replies + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From c19ee167ec439869e6c645b9a1de5f47b96dd107 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:35 +0200 Subject: [PATCH 057/188] New translations app.json (Scottish Gaelic) --- .../StringsConvertor/input/gd_GB/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/gd_GB/app.json b/Localization/StringsConvertor/input/gd_GB/app.json index 520293d4..23c893c8 100644 --- a/Localization/StringsConvertor/input/gd_GB/app.json +++ b/Localization/StringsConvertor/input/gd_GB/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Seall pròifil a’ chleachdaiche", "content_warning": "Rabhadh susbainte", "media_content_warning": "Thoir gnogag àite sam bith gus a nochdadh", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Cuir bhòt", "closed": "Dùinte" @@ -141,7 +142,11 @@ "favorite": "Cuir ris na h-annsachdan", "unfavorite": "Thoir air falbh o na h-annsachdan", "menu": "Clàr-taice", - "hide": "Falaich" + "hide": "Falaich", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Dì-bhac an cunntas", "message": "Dearbh dì-bhacadh %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Modh dubh dorcha", "disable_avatar_animation": "Cuir beothachadh nan avataran à comas", "disable_emoji_animation": "Cuir beothachadh nan Emojis à comas", - "using_default_browser": "Cleachd am brabhsair bunaiteach airson ceanglaichean fhosgladh" + "using_default_browser": "Cleachd am brabhsair bunaiteach airson ceanglaichean fhosgladh", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "An earrann ràsanach", From 4795be5ed4ae5b1a34b991ea56965a28bd7b727a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:35 +0200 Subject: [PATCH 058/188] New translations Localizable.stringsdict (Scottish Gaelic) --- .../input/gd_GB/Localizable.stringsdict | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict index 7a54f553..5bcd17bf 100644 --- a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict @@ -142,6 +142,26 @@ %ld brosnachadh + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + two + %ld replies + few + %ld replies + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From a02704241ad26ba4f255a789233e9ba96eeb7203 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:36 +0200 Subject: [PATCH 059/188] New translations Localizable.stringsdict (Kurmanji (Kurdish)) --- .../input/kmr_TR/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict index 8ae1b812..e9da7245 100644 --- a/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld ji nû ve nivîsandin + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From c0b3e43bbc815d1553dd9b88ea1a9dcb61fcd624 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:37 +0200 Subject: [PATCH 060/188] New translations app.json (Swedish, Finland) --- .../StringsConvertor/input/sv_FI/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/sv_FI/app.json b/Localization/StringsConvertor/input/sv_FI/app.json index 669ee437..5bb7c8b7 100644 --- a/Localization/StringsConvertor/input/sv_FI/app.json +++ b/Localization/StringsConvertor/input/sv_FI/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Näytä tili", "content_warning": "Sisältövaroitus", "media_content_warning": "Napauta mistä tahansa paljastaaksesi", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Vote", "closed": "Suljettu" @@ -141,7 +142,11 @@ "favorite": "Favorite", "unfavorite": "Unfavorite", "menu": "Valikko", - "hide": "Dölj" + "hide": "Dölj", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Unblock Account", "message": "Confirm to unblock %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Todellinen mustan tumma tila", "disable_avatar_animation": "Poista käytöstä animoidut avatarit", "disable_emoji_animation": "Poista käytöstä animoidut emojit", - "using_default_browser": "Käytä oletusselainta linkkien avaamiseen" + "using_default_browser": "Käytä oletusselainta linkkien avaamiseen", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "Tylsä alue", From 3b3c9033dba1007c0049deced530a25891f8d2a6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:40 +0200 Subject: [PATCH 061/188] New translations Localizable.stringsdict (Swedish, Finland) --- .../input/sv_FI/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict b/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict index eec977a6..43231214 100644 --- a/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/sv_FI/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld edelleen jakoa + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From be327584569f44e7b04793d9f94c17dbdf33c709 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:41 +0200 Subject: [PATCH 062/188] New translations app.json (Kabyle) --- .../StringsConvertor/input/kab_KAB/app.json | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/kab_KAB/app.json b/Localization/StringsConvertor/input/kab_KAB/app.json index 74c16795..feb25700 100644 --- a/Localization/StringsConvertor/input/kab_KAB/app.json +++ b/Localization/StringsConvertor/input/kab_KAB/app.json @@ -130,6 +130,7 @@ "show_user_profile": "Ssken-d amaɣnu n useqdac", "content_warning": "Alɣu n ugbur", "media_content_warning": "Sit anida tebɣiḍ i wakken ad twaliḍ", + "tap_to_reveal": "Tap to reveal", "poll": { "vote": "Dɣeṛ", "closed": "Ifukk" @@ -141,7 +142,11 @@ "favorite": "Anurif", "unfavorite": "Kkes seg yismenyifen", "menu": "Umuɣ", - "hide": "Ffer" + "hide": "Ffer", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { "url": "URL", @@ -440,6 +445,12 @@ "title": "Kkes asewḥel i umiḍan", "message": "Sentem tukksa n usgugem i %s" } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" } }, "follower": { @@ -541,7 +552,8 @@ "true_black_dark_mode": "Askar aberkan n tidet", "disable_avatar_animation": "Sens ivaṭaren yettembiwilen", "disable_emoji_animation": "Sens imujiten yettembiwilen", - "using_default_browser": "Seqdec iminig amezwer i twaledyawt n yiseɣwan" + "using_default_browser": "Seqdec iminig amezwer i twaledyawt n yiseɣwan", + "open_links_in_mastodon": "Open links in Mastodon" }, "boring_zone": { "title": "Tamnaḍt yessefcalen", From 5d7d147c2b5b8f811456b0c57a8857ab73a5d67a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 04:55:42 +0200 Subject: [PATCH 063/188] New translations Localizable.stringsdict (Kabyle) --- .../input/kab_KAB/Localizable.stringsdict | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Localization/StringsConvertor/input/kab_KAB/Localizable.stringsdict b/Localization/StringsConvertor/input/kab_KAB/Localizable.stringsdict index 8a2bac9e..c3d72dda 100644 --- a/Localization/StringsConvertor/input/kab_KAB/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/kab_KAB/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld n uɛiwed n usuffeɣ + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From d623ebc277ea5c0b7b1049773b4abfc20bee1d77 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 06:49:42 +0200 Subject: [PATCH 064/188] New translations app.json (Catalan) --- .../StringsConvertor/input/ca_ES/app.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index d7008bff..1c73b917 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -130,7 +130,7 @@ "show_user_profile": "Mostra el perfil de l'usuari", "content_warning": "Advertència de Contingut", "media_content_warning": "Toca qualsevol lloc per mostrar", - "tap_to_reveal": "Tap to reveal", + "tap_to_reveal": "Toca per a mostrar", "poll": { "vote": "Vota", "closed": "Finalitzada" @@ -143,10 +143,10 @@ "unfavorite": "Desfer Favorit", "menu": "Menú", "hide": "Amaga", - "show_image": "Show image", - "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_image": "Mostra la imatge", + "show_gif": "Mostra el GIF", + "show_video_player": "Mostra el reproductor de vídeo", + "tap_then_hold_to_show_menu": "Toca i manté per a veure el menú" }, "tag": { "url": "URL", @@ -447,10 +447,10 @@ } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", - "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "show_avatar_image": "Mostra l'imatge del avatar", + "edit_avatar_image": "Edita l'imatge del avatar", + "show_banner_image": "Mostra l'imatge del bàner", + "double_tap_to_open_the_list": "Doble toc per a veure la llista" } }, "follower": { @@ -553,7 +553,7 @@ "disable_avatar_animation": "Desactiva avatars animats", "disable_emoji_animation": "Desactiva emojis animats", "using_default_browser": "Utilitza el navegador predeterminat per a obrir enllaços", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "Obre enllaços a Mastodon" }, "boring_zone": { "title": "La Zona Avorrida", From cadc56d73ed82c8ae9b0ec93ee1fce40511bc13f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 06:49:44 +0200 Subject: [PATCH 065/188] New translations Localizable.stringsdict (Catalan) --- .../StringsConvertor/input/ca_ES/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict index 9475b3e2..dfbd38c0 100644 --- a/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ca_ES/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 Resposta other - %ld replies + %ld respostes plural.count.vote From 3195ea4cc15b165ffd036fc8d480b593a19b023c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 06:49:45 +0200 Subject: [PATCH 066/188] New translations app.json (Spanish, Argentina) --- .../StringsConvertor/input/es_AR/app.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Localization/StringsConvertor/input/es_AR/app.json b/Localization/StringsConvertor/input/es_AR/app.json index ab0517da..c90fcb35 100644 --- a/Localization/StringsConvertor/input/es_AR/app.json +++ b/Localization/StringsConvertor/input/es_AR/app.json @@ -130,7 +130,7 @@ "show_user_profile": "Mostrar perfil de usuario", "content_warning": "Advertencia de contenido", "media_content_warning": "Toca en cualquier lugar para mostrar", - "tap_to_reveal": "Tap to reveal", + "tap_to_reveal": "Tocá para mostrar", "poll": { "vote": "Votar", "closed": "Cerrada" @@ -143,10 +143,10 @@ "unfavorite": "Dejar de marcar como favorito", "menu": "Menú", "hide": "Ocultar", - "show_image": "Show image", - "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_image": "Mostrar imagen", + "show_gif": "Mostrar GIF", + "show_video_player": "Mostrar reproductor de video", + "tap_then_hold_to_show_menu": "Tocá y mantené presionado para mostrar el menú" }, "tag": { "url": "Dirección web", @@ -447,10 +447,10 @@ } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", - "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "show_avatar_image": "Mostrar imagen de avatar", + "edit_avatar_image": "Editar imagen de avatar", + "show_banner_image": "Mostrar imagen de banner", + "double_tap_to_open_the_list": "Tocá dos veces para abrir la lista" } }, "follower": { @@ -553,7 +553,7 @@ "disable_avatar_animation": "Deshabilitar avatares animados", "disable_emoji_animation": "Deshabilitar emojis animados", "using_default_browser": "Usar navegador web predeterminado para abrir enlaces", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "Abrir enlaces en Mastodon" }, "boring_zone": { "title": "La zona aburrida", From 1b8f27340122cb2662d6f01ca6a25c0338d374f4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 06:49:46 +0200 Subject: [PATCH 067/188] New translations Localizable.stringsdict (Spanish, Argentina) --- .../StringsConvertor/input/es_AR/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict index c63073f4..9d1fdadb 100644 --- a/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es_AR/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 respuesta other - %ld replies + %ld respuestas plural.count.vote From 1c981910c65a3b9baca587f426b7f0bd29fcf0f1 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 30 Mar 2022 15:23:22 +0800 Subject: [PATCH 068/188] feat: make the text input hover when keyboard display --- .../MastodonRegisterViewController.swift | 75 ++----------------- 1 file changed, 7 insertions(+), 68 deletions(-) diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift index bd2db3d4..26060c2c 100644 --- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift @@ -11,6 +11,7 @@ import MastodonSDK import os.log import PhotosUI import UIKit +import MastodonUI import MastodonAsset import MastodonLocalization @@ -132,12 +133,12 @@ extension MastodonRegisterViewController { viewModel.setupDiffableDataSource(tableView: tableView) -// KeyboardResponderService -// .configure( -// scrollView: tableView, -// layoutNeedsUpdate: viewModel.viewDidAppear.eraseToAnyPublisher() -// ) -// .store(in: &disposeBag) + KeyboardResponderService + .configure( + scrollView: tableView, + layoutNeedsUpdate: viewModel.viewDidAppear.eraseToAnyPublisher() + ) + .store(in: &disposeBag) // gesture view.addGestureRecognizer(tapGestureRecognizer) @@ -403,65 +404,3 @@ extension MastodonRegisterViewController { } } - -extension MastodonRegisterViewController: UITextFieldDelegate { -// func textFieldDidBeginEditing(_ textField: UITextField) { -// let text = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" -// -// switch textField { -// case usernameTextField: -// viewModel.username.value = text -// case displayNameTextField: -// viewModel.displayName.value = text -// case emailTextField: -// viewModel.email.value = text -// case passwordTextField: -// viewModel.password.value = text -// case reasonTextField: -// viewModel.reason.value = text -// default: -// break -// } -// } -// -// func textFieldDidEndEditing(_ textField: UITextField) { -// let text = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" -// -// switch textField { -// case usernameTextField: -// viewModel.username.value = text -// case displayNameTextField: -// viewModel.displayName.value = text -// case emailTextField: -// viewModel.email.value = text -// case passwordTextField: -// viewModel.password.value = text -// case reasonTextField: -// viewModel.reason.value = text -// default: -// break -// } -// } -// -// func textFieldShouldReturn(_ textField: UITextField) -> Bool { -// switch textField { -// case usernameTextField: -// displayNameTextField.becomeFirstResponder() -// case displayNameTextField: -// emailTextField.becomeFirstResponder() -// case emailTextField: -// passwordTextField.becomeFirstResponder() -// case passwordTextField: -// if viewModel.approvalRequired { -// reasonTextField.becomeFirstResponder() -// } else { -// passwordTextField.resignFirstResponder() -// } -// case reasonTextField: -// reasonTextField.resignFirstResponder() -// default: -// break -// } -// return true -// } -} From 116e9c143ca2863aa4cedfdfd16c778b83771761 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 30 Mar 2022 15:23:59 +0800 Subject: [PATCH 069/188] chore: fix the username text field right label too long in sign-up form --- .../Register/Cell/MastodonRegisterTextFieldTableViewCell.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterTextFieldTableViewCell.swift b/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterTextFieldTableViewCell.swift index 3daa2eb1..15f23483 100644 --- a/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterTextFieldTableViewCell.swift +++ b/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterTextFieldTableViewCell.swift @@ -115,6 +115,7 @@ extension MastodonRegisterTextFieldTableViewCell { label.font = MastodonRegisterTextFieldTableViewCell.textFieldLabelFont label.textColor = Asset.Colors.Label.primary.color label.text = text + label.lineBreakMode = .byTruncatingMiddle label.translatesAutoresizingMaskIntoConstraints = false containerView.addSubview(label) @@ -123,6 +124,7 @@ extension MastodonRegisterTextFieldTableViewCell { label.leadingAnchor.constraint(equalTo: paddingView.trailingAnchor), containerView.trailingAnchor.constraint(equalTo: label.trailingAnchor, constant: 16), label.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), + label.widthAnchor.constraint(lessThanOrEqualToConstant: 180).priority(.required - 1), ]) return containerView }() From 712d79be89b1f1ce985d0fbb4f554d70b2e1ac08 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 10:28:53 +0200 Subject: [PATCH 070/188] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 23d309d2..34848cad 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -129,8 +129,8 @@ "show_post": "إظهار منشور", "show_user_profile": "إظهار الملف التعريفي للمُستخدِم", "content_warning": "تحذير المُحتوى", - "media_content_warning": "انقر للكشف", - "tap_to_reveal": "Tap to reveal", + "media_content_warning": "اُنقُر لِلكَشف", + "tap_to_reveal": "اُنقُر لِلكَشف", "poll": { "vote": "صَوِّت", "closed": "انتهى" @@ -143,10 +143,10 @@ "unfavorite": "إزالة التفضيل", "menu": "القائمة", "hide": "إخفاء", - "show_image": "Show image", - "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_image": "أظْهِرِ الصُّورَة", + "show_gif": "إظهارُ GIF", + "show_video_player": "إظْهارُ مُشَغِّلِ المَقاطِعِ المَرئِيَّة", + "tap_then_hold_to_show_menu": "اُنقُر مُطَوَّلًا لِإظْهَارِ القائِمَة" }, "tag": { "url": "عنوان URL", @@ -447,10 +447,10 @@ } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", + "show_avatar_image": "إظْهارُ الصُّورَةِ الرَّمزِيَّة", + "edit_avatar_image": "تَحريرُ الصُّورَةِ الرَّمزِيَّة", "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "double_tap_to_open_the_list": "اُنقُر نَقرًا مُزدَوَجًا لِفَتحِ القائِمَة" } }, "follower": { @@ -553,7 +553,7 @@ "disable_avatar_animation": "تَعطيلُ الصوَرِ الرمزيَّةِ المُتحرِّكَة", "disable_emoji_animation": "تَعطيلُ الرُموزِ التَّعبيريَّةِ المُتحرِّكَة", "using_default_browser": "اِستِخدامُ المُتصفِّحِ الاِفتراضي لِفتحِ الرَّوابِط", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "فَتحُ الرَّوابِطِ فِي مَاستودُون" }, "boring_zone": { "title": "المنطِقَةُ المُملَّة", From 954b0291dee32ff2a95b1ccd80d399d445f7bc0a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 11:38:31 +0200 Subject: [PATCH 071/188] New translations app.json (Arabic) --- .../StringsConvertor/input/ar_SA/app.json | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 34848cad..6a6fdcd4 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -103,7 +103,7 @@ "common": { "switch_to_tab": "التبديل إلى %s", "compose_new_post": "تأليف منشور جديد", - "show_favorites": "إظهار المُفضَّلة", + "show_favorites": "أظْهِر المُفضَّلة", "open_settings": "فَتحُ الإعدادات" }, "timeline": { @@ -126,8 +126,8 @@ "status": { "user_reblogged": "أعادَ %s تَدوينَها", "user_replied_to": "رَدًا على %s", - "show_post": "إظهار منشور", - "show_user_profile": "إظهار الملف التعريفي للمُستخدِم", + "show_post": "أظْهِر مَنشور", + "show_user_profile": "أظْهِر المِلَفَّ التَّعريفِيَّ لِلمُستَخدِم", "content_warning": "تحذير المُحتوى", "media_content_warning": "اُنقُر لِلكَشف", "tap_to_reveal": "اُنقُر لِلكَشف", @@ -144,8 +144,8 @@ "menu": "القائمة", "hide": "إخفاء", "show_image": "أظْهِرِ الصُّورَة", - "show_gif": "إظهارُ GIF", - "show_video_player": "إظْهارُ مُشَغِّلِ المَقاطِعِ المَرئِيَّة", + "show_gif": "أظْهِر GIF", + "show_video_player": "أظْهِر مُشَغِّلَ المَقاطِعِ المَرئِيَّة", "tap_then_hold_to_show_menu": "اُنقُر مُطَوَّلًا لِإظْهَارِ القائِمَة" }, "tag": { @@ -189,7 +189,7 @@ "loader": { "load_missing_posts": "تحميل المَنشورات المَفقودَة", "loading_missing_posts": "يَجري تحميل المَنشورات المَفقودَة...", - "show_more_replies": "إظهار مَزيد مِنَ الرُّدود" + "show_more_replies": "أظْهِر مَزيدًا مِنَ الرُّدود" }, "header": { "no_status_found": "لَم يُعْثَر على مَنشورات", @@ -447,9 +447,9 @@ } }, "accessibility": { - "show_avatar_image": "إظْهارُ الصُّورَةِ الرَّمزِيَّة", + "show_avatar_image": "أظْهِر الصُّورَةَ الرَّمزِيَّة", "edit_avatar_image": "تَحريرُ الصُّورَةِ الرَّمزِيَّة", - "show_banner_image": "Show banner image", + "show_banner_image": "أظْهِر صُورَةَ الرَّايَة", "double_tap_to_open_the_list": "اُنقُر نَقرًا مُزدَوَجًا لِفَتحِ القائِمَة" } }, @@ -509,8 +509,8 @@ "poll_has_ended": "انتهى استطلاعُ الرأي" }, "keyobard": { - "show_everything": "إظهار كل شيء", - "show_mentions": "إظهار الإشارات" + "show_everything": "أظْهِر كُلَّ شَيء", + "show_mentions": "أظْهِر الإشارَات" } }, "thread": { @@ -590,12 +590,12 @@ "preview": { "keyboard": { "close_preview": "إغلاق المُعايَنَة", - "show_next": "إظهار التالي", - "show_previous": "إظهار السابق" + "show_next": "أظْهِر التَّالي", + "show_previous": "أظْهِر السَّابِق" } }, "account_list": { - "tab_bar_hint": "المِلف المُحدَّد حاليًا: %s. انقر نقرًا مزدوجًا مع الاستمرار لإظهار مُبدِّل الحِساب", + "tab_bar_hint": "المِلَفُّ المُحدَّدُ حالِيًّا: %s. اُنقُر نَقرًا مُزدَوَجًا مَعَ الاِستِمرارِ لِإظهارِ مُبدِّلِ الحِساب", "dismiss_account_switcher": "تجاهُل مبدِّل الحِساب", "add_account": "إضافَةُ حِساب" }, From b1b9a53cf68869307b942962b835914b9146f3fc Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 11:38:33 +0200 Subject: [PATCH 072/188] New translations Localizable.stringsdict (Arabic) --- .../StringsConvertor/input/ar_SA/Localizable.stringsdict | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index 4ecfe591..8d181e07 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -191,7 +191,7 @@ many %ld replies other - %ld replies + %ld رَدّ plural.count.vote From 0acf84ba8e1df700901878b48b52356b3e1d08c5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 12:47:54 +0200 Subject: [PATCH 073/188] New translations app.json (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/app.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 582ff144..ffa34577 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -130,7 +130,7 @@ "show_user_profile": "Profîla bikarhêner nîşan bide", "content_warning": "Hişyariya naverokê", "media_content_warning": "Ji bo eşkerekirinê li derekî bitikîne", - "tap_to_reveal": "Tap to reveal", + "tap_to_reveal": "Ji bo dîtinê bitikîne", "poll": { "vote": "Deng bide", "closed": "Girtî" @@ -143,10 +143,10 @@ "unfavorite": "Nebijarte", "menu": "Kulîn", "hide": "Veşêre", - "show_image": "Show image", - "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_image": "Wêneyê nîşan bide", + "show_gif": "GIF nîşan bide", + "show_video_player": "Lêdera vîdyoyê nîşan bide", + "tap_then_hold_to_show_menu": "Ji bo nîşandana menuyê dirêj bitikîne" }, "tag": { "url": "URL", @@ -447,10 +447,10 @@ } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", - "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "show_avatar_image": "Wêneya avatar nîşan bide", + "edit_avatar_image": "Wêneya avatar serrast bike", + "show_banner_image": "Wêneya paşrûyê nîşan bide", + "double_tap_to_open_the_list": "Ducaran bitikîne bo vekirina listeyê" } }, "follower": { @@ -553,7 +553,7 @@ "disable_avatar_animation": "Avatarên anîmasyonî neçalak bike", "disable_emoji_animation": "Emojiyên anîmasyonî neçalak bike", "using_default_browser": "Ji bo vekirina girêdanan geroka berdest bi kar bîne", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "Girêdanan di Mastodon de veke" }, "boring_zone": { "title": "Devera acizker", From d7f2ffec57da0155564d4fdee0c0b454d523328e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 12:47:55 +0200 Subject: [PATCH 074/188] New translations Localizable.stringsdict (Kurmanji (Kurdish)) --- .../StringsConvertor/input/kmr_TR/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict index e9da7245..0fa7d821 100644 --- a/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/kmr_TR/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 bersiv other - %ld replies + %ld bersiv plural.count.vote From afc3a0ae66e2410d5f99d28bcb90979b4200a4f7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 17:57:22 +0200 Subject: [PATCH 075/188] New translations app.json (Scottish Gaelic) --- .../StringsConvertor/input/gd_GB/app.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Localization/StringsConvertor/input/gd_GB/app.json b/Localization/StringsConvertor/input/gd_GB/app.json index 23c893c8..236ad473 100644 --- a/Localization/StringsConvertor/input/gd_GB/app.json +++ b/Localization/StringsConvertor/input/gd_GB/app.json @@ -130,7 +130,7 @@ "show_user_profile": "Seall pròifil a’ chleachdaiche", "content_warning": "Rabhadh susbainte", "media_content_warning": "Thoir gnogag àite sam bith gus a nochdadh", - "tap_to_reveal": "Tap to reveal", + "tap_to_reveal": "Thoir gnogag gus a nochdadh", "poll": { "vote": "Cuir bhòt", "closed": "Dùinte" @@ -143,10 +143,10 @@ "unfavorite": "Thoir air falbh o na h-annsachdan", "menu": "Clàr-taice", "hide": "Falaich", - "show_image": "Show image", - "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_image": "Seall an dealbh", + "show_gif": "Seall an GIF", + "show_video_player": "Seall cluicheadair video", + "tap_then_hold_to_show_menu": "Thoir gnogag ’s cùm sìos a shealltainn a’ chlàir-thaice" }, "tag": { "url": "URL", @@ -447,10 +447,10 @@ } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", - "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "show_avatar_image": "Seall dealbh an avatar", + "edit_avatar_image": "Deasaich dealbh an avatar", + "show_banner_image": "Seall dealbh brataich", + "double_tap_to_open_the_list": "Thoir gnogag dhùbailte a dh’fhosgladh na liosta" } }, "follower": { @@ -553,7 +553,7 @@ "disable_avatar_animation": "Cuir beothachadh nan avataran à comas", "disable_emoji_animation": "Cuir beothachadh nan Emojis à comas", "using_default_browser": "Cleachd am brabhsair bunaiteach airson ceanglaichean fhosgladh", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "Fosgail ceanglaichean ann am Mastodon" }, "boring_zone": { "title": "An earrann ràsanach", From 9919a42abf44b713d0cfa6c5bbb72380e096e6cf Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 30 Mar 2022 17:57:24 +0200 Subject: [PATCH 076/188] New translations Localizable.stringsdict (Scottish Gaelic) --- .../StringsConvertor/input/gd_GB/Localizable.stringsdict | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict index 5bcd17bf..b149323e 100644 --- a/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/gd_GB/Localizable.stringsdict @@ -153,13 +153,13 @@ NSStringFormatValueTypeKey ld one - 1 reply + %ld fhreagairt two - %ld replies + %ld fhreagairt few - %ld replies + %ld freagairtean other - %ld replies + %ld freagairt plural.count.vote From c2e168fc0fca4d9a7a79a0464dd3507e708cae04 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 04:56:13 +0200 Subject: [PATCH 077/188] New translations app.json (Vietnamese) --- .../StringsConvertor/input/vi_VN/app.json | 608 ++++++++++++++++++ 1 file changed, 608 insertions(+) create mode 100644 Localization/StringsConvertor/input/vi_VN/app.json diff --git a/Localization/StringsConvertor/input/vi_VN/app.json b/Localization/StringsConvertor/input/vi_VN/app.json new file mode 100644 index 00000000..f0dc0ebf --- /dev/null +++ b/Localization/StringsConvertor/input/vi_VN/app.json @@ -0,0 +1,608 @@ +{ + "common": { + "alerts": { + "common": { + "please_try_again": "Please try again.", + "please_try_again_later": "Please try again later." + }, + "sign_up_failure": { + "title": "Sign Up Failure" + }, + "server_error": { + "title": "Server Error" + }, + "vote_failure": { + "title": "Vote Failure", + "poll_ended": "The poll has ended" + }, + "discard_post_content": { + "title": "Discard Draft", + "message": "Confirm to discard composed post content." + }, + "publish_post_failure": { + "title": "Publish Failure", + "message": "Failed to publish the post.\nPlease check your internet connection.", + "attachments_message": { + "video_attach_with_photo": "Cannot attach a video to a post that already contains images.", + "more_than_one_video": "Cannot attach more than one video." + } + }, + "edit_profile_failure": { + "title": "Edit Profile Error", + "message": "Cannot edit profile. Please try again." + }, + "sign_out": { + "title": "Sign Out", + "message": "Are you sure you want to sign out?", + "confirm": "Sign Out" + }, + "block_domain": { + "title": "Are you really, really sure you want to block the entire %s? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain and any of your followers from that domain will be removed.", + "block_entire_domain": "Block Domain" + }, + "save_photo_failure": { + "title": "Save Photo Failure", + "message": "Please enable the photo library access permission to save the photo." + }, + "delete_post": { + "title": "Delete Post", + "message": "Are you sure you want to delete this post?" + }, + "clean_cache": { + "title": "Clean Cache", + "message": "Successfully cleaned %s cache." + } + }, + "controls": { + "actions": { + "back": "Back", + "next": "Next", + "previous": "Previous", + "open": "Open", + "add": "Add", + "remove": "Remove", + "edit": "Edit", + "save": "Save", + "ok": "OK", + "done": "Done", + "confirm": "Confirm", + "continue": "Continue", + "compose": "Compose", + "cancel": "Cancel", + "discard": "Discard", + "try_again": "Try Again", + "take_photo": "Take Photo", + "save_photo": "Save Photo", + "copy_photo": "Copy Photo", + "sign_in": "Sign In", + "sign_up": "Sign Up", + "see_more": "See More", + "preview": "Preview", + "share": "Share", + "share_user": "Share %s", + "share_post": "Share Post", + "open_in_safari": "Open in Safari", + "open_in_browser": "Open in Browser", + "find_people": "Find people to follow", + "manually_search": "Manually search instead", + "skip": "Skip", + "reply": "Reply", + "report_user": "Report %s", + "block_domain": "Block %s", + "unblock_domain": "Unblock %s", + "settings": "Settings", + "delete": "Delete" + }, + "tabs": { + "home": "Home", + "search": "Search", + "notification": "Notification", + "profile": "Profile" + }, + "keyboard": { + "common": { + "switch_to_tab": "Switch to %s", + "compose_new_post": "Compose New Post", + "show_favorites": "Show Favorites", + "open_settings": "Open Settings" + }, + "timeline": { + "previous_status": "Previous Post", + "next_status": "Next Post", + "open_status": "Open Post", + "open_author_profile": "Open Author's Profile", + "open_reblogger_profile": "Open Reblogger's Profile", + "reply_status": "Reply to Post", + "toggle_reblog": "Toggle Reblog on Post", + "toggle_favorite": "Toggle Favorite on Post", + "toggle_content_warning": "Toggle Content Warning", + "preview_image": "Preview Image" + }, + "segmented_control": { + "previous_section": "Previous Section", + "next_section": "Next Section" + } + }, + "status": { + "user_reblogged": "%s reblogged", + "user_replied_to": "Replied to %s", + "show_post": "Show Post", + "show_user_profile": "Show user profile", + "content_warning": "Content Warning", + "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", + "poll": { + "vote": "Vote", + "closed": "Closed" + }, + "actions": { + "reply": "Reply", + "reblog": "Reblog", + "unreblog": "Undo reblog", + "favorite": "Favorite", + "unfavorite": "Unfavorite", + "menu": "Menu", + "hide": "Hide", + "show_image": "Show image", + "show_gif": "Show GIF", + "show_video_player": "Show video player", + "tap_then_hold_to_show_menu": "Tap then hold to show menu" + }, + "tag": { + "url": "URL", + "mention": "Mention", + "link": "Link", + "hashtag": "Hashtag", + "email": "Email", + "emoji": "Emoji" + }, + "visibility": { + "unlisted": "Everyone can see this post but not display in the public timeline.", + "private": "Only their followers can see this post.", + "private_from_me": "Only my followers can see this post.", + "direct": "Only mentioned user can see this post." + } + }, + "friendship": { + "follow": "Follow", + "following": "Following", + "request": "Request", + "pending": "Pending", + "block": "Block", + "block_user": "Block %s", + "block_domain": "Block %s", + "unblock": "Unblock", + "unblock_user": "Unblock %s", + "blocked": "Blocked", + "mute": "Mute", + "mute_user": "Mute %s", + "unmute": "Unmute", + "unmute_user": "Unmute %s", + "muted": "Muted", + "edit_info": "Edit Info" + }, + "timeline": { + "filtered": "Filtered", + "timestamp": { + "now": "Now" + }, + "loader": { + "load_missing_posts": "Load missing posts", + "loading_missing_posts": "Loading missing posts...", + "show_more_replies": "Show more replies" + }, + "header": { + "no_status_found": "No Post Found", + "blocking_warning": "You can’t view this user's profile\nuntil you unblock them.\nYour profile looks like this to them.", + "user_blocking_warning": "You can’t view %s’s profile\nuntil you unblock them.\nYour profile looks like this to them.", + "blocked_warning": "You can’t view this user’s profile\nuntil they unblock you.", + "user_blocked_warning": "You can’t view %s’s profile\nuntil they unblock you.", + "suspended_warning": "This user has been suspended.", + "user_suspended_warning": "%s’s account has been suspended." + } + } + } + }, + "scene": { + "welcome": { + "slogan": "Social networking\nback in your hands.", + "get_started": "Get Started", + "log_in": "Log In" + }, + "server_picker": { + "title": "Mastodon is made of users in different communities.", + "subtitle": "Pick a community based on your interests, region, or a general purpose one.", + "subtitle_extend": "Pick a community based on your interests, region, or a general purpose one. Each community is operated by an entirely independent organization or individual.", + "button": { + "category": { + "all": "All", + "all_accessiblity_description": "Category: All", + "academia": "academia", + "activism": "activism", + "food": "food", + "furry": "furry", + "games": "games", + "general": "general", + "journalism": "journalism", + "lgbt": "lgbt", + "regional": "regional", + "art": "art", + "music": "music", + "tech": "tech" + }, + "see_less": "See Less", + "see_more": "See More" + }, + "label": { + "language": "LANGUAGE", + "users": "USERS", + "category": "CATEGORY" + }, + "input": { + "placeholder": "Search communities" + }, + "empty_state": { + "finding_servers": "Finding available servers...", + "bad_network": "Something went wrong while loading the data. Check your internet connection.", + "no_results": "No results" + } + }, + "register": { + "title": "Let’s get you set up on %s", + "input": { + "avatar": { + "delete": "Delete" + }, + "username": { + "placeholder": "username", + "duplicate_prompt": "This username is taken." + }, + "display_name": { + "placeholder": "display name" + }, + "email": { + "placeholder": "email" + }, + "password": { + "placeholder": "password", + "require": "Your password needs at least:", + "character_limit": "8 characters", + "accessibility": { + "checked": "checked", + "unchecked": "unchecked" + }, + "hint": "Your password needs at least eight characters" + }, + "invite": { + "registration_user_invite_request": "Why do you want to join?" + } + }, + "error": { + "item": { + "username": "Username", + "email": "Email", + "password": "Password", + "agreement": "Agreement", + "locale": "Locale", + "reason": "Reason" + }, + "reason": { + "blocked": "%s contains a disallowed email provider", + "unreachable": "%s does not seem to exist", + "taken": "%s is already in use", + "reserved": "%s is a reserved keyword", + "accepted": "%s must be accepted", + "blank": "%s is required", + "invalid": "%s is invalid", + "too_long": "%s is too long", + "too_short": "%s is too short", + "inclusion": "%s is not a supported value" + }, + "special": { + "username_invalid": "Username must only contain alphanumeric characters and underscores", + "username_too_long": "Username is too long (can’t be longer than 30 characters)", + "email_invalid": "This is not a valid email address", + "password_too_short": "Password is too short (must be at least 8 characters)" + } + } + }, + "server_rules": { + "title": "Some ground rules.", + "subtitle": "These are set and enforced by the %s moderators.", + "prompt": "By continuing, you’re subject to the terms of service and privacy policy for %s.", + "terms_of_service": "terms of service", + "privacy_policy": "privacy policy", + "button": { + "confirm": "I Agree" + } + }, + "confirm_email": { + "title": "One last thing.", + "subtitle": "Tap the link we emailed to you to verify your account.", + "button": { + "open_email_app": "Open Email App", + "resend": "Resend" + }, + "dont_receive_email": { + "title": "Check your email", + "description": "Check if your email address is correct as well as your junk folder if you haven’t.", + "resend_email": "Resend Email" + }, + "open_email_app": { + "title": "Check your inbox.", + "description": "We just sent you an email. Check your junk folder if you haven’t.", + "mail": "Mail", + "open_email_client": "Open Email Client" + } + }, + "home_timeline": { + "title": "Home", + "navigation_bar_state": { + "offline": "Offline", + "new_posts": "See new posts", + "published": "Published!", + "Publishing": "Publishing post..." + } + }, + "suggestion_account": { + "title": "Find People to Follow", + "follow_explain": "When you follow someone, you’ll see their posts in your home feed." + }, + "compose": { + "title": { + "new_post": "New Post", + "new_reply": "New Reply" + }, + "media_selection": { + "camera": "Take Photo", + "photo_library": "Photo Library", + "browse": "Browse" + }, + "content_input_placeholder": "Type or paste what’s on your mind", + "compose_action": "Publish", + "replying_to_user": "replying to %s", + "attachment": { + "photo": "photo", + "video": "video", + "attachment_broken": "This %s is broken and can’t be\nuploaded to Mastodon.", + "description_photo": "Describe the photo for the visually-impaired...", + "description_video": "Describe the video for the visually-impaired..." + }, + "poll": { + "duration_time": "Duration: %s", + "thirty_minutes": "30 minutes", + "one_hour": "1 Hour", + "six_hours": "6 Hours", + "one_day": "1 Day", + "three_days": "3 Days", + "seven_days": "7 Days", + "option_number": "Option %ld" + }, + "content_warning": { + "placeholder": "Write an accurate warning here..." + }, + "visibility": { + "public": "Public", + "unlisted": "Unlisted", + "private": "Followers only", + "direct": "Only people I mention" + }, + "auto_complete": { + "space_to_add": "Space to add" + }, + "accessibility": { + "append_attachment": "Add Attachment", + "append_poll": "Add Poll", + "remove_poll": "Remove Poll", + "custom_emoji_picker": "Custom Emoji Picker", + "enable_content_warning": "Enable Content Warning", + "disable_content_warning": "Disable Content Warning", + "post_visibility_menu": "Post Visibility Menu" + }, + "keyboard": { + "discard_post": "Discard Post", + "publish_post": "Publish Post", + "toggle_poll": "Toggle Poll", + "toggle_content_warning": "Toggle Content Warning", + "append_attachment_entry": "Add Attachment - %s", + "select_visibility_entry": "Select Visibility - %s" + } + }, + "profile": { + "dashboard": { + "posts": "posts", + "following": "following", + "followers": "followers" + }, + "fields": { + "add_row": "Add Row", + "placeholder": { + "label": "Label", + "content": "Content" + } + }, + "segmented_control": { + "posts": "Posts", + "replies": "Replies", + "posts_and_replies": "Posts and Replies", + "media": "Media", + "about": "About" + }, + "relationship_action_alert": { + "confirm_mute_user": { + "title": "Mute Account", + "message": "Confirm to mute %s" + }, + "confirm_unmute_user": { + "title": "Unmute Account", + "message": "Confirm to unmute %s" + }, + "confirm_block_user": { + "title": "Block Account", + "message": "Confirm to block %s" + }, + "confirm_unblock_user": { + "title": "Unblock Account", + "message": "Confirm to unblock %s" + } + }, + "accessibility": { + "show_avatar_image": "Show avatar image", + "edit_avatar_image": "Edit avatar image", + "show_banner_image": "Show banner image", + "double_tap_to_open_the_list": "Double tap to open the list" + } + }, + "follower": { + "footer": "Followers from other servers are not displayed." + }, + "following": { + "footer": "Follows from other servers are not displayed." + }, + "search": { + "title": "Search", + "search_bar": { + "placeholder": "Search hashtags and users", + "cancel": "Cancel" + }, + "recommend": { + "button_text": "See All", + "hash_tag": { + "title": "Trending on Mastodon", + "description": "Hashtags that are getting quite a bit of attention", + "people_talking": "%s people are talking" + }, + "accounts": { + "title": "Accounts you might like", + "description": "You may like to follow these accounts", + "follow": "Follow" + } + }, + "searching": { + "segment": { + "all": "All", + "people": "People", + "hashtags": "Hashtags", + "posts": "Posts" + }, + "empty_state": { + "no_results": "No results" + }, + "recent_search": "Recent searches", + "clear": "Clear" + } + }, + "favorite": { + "title": "Your Favorites" + }, + "notification": { + "title": { + "Everything": "Everything", + "Mentions": "Mentions" + }, + "notification_description": { + "followed_you": "followed you", + "favorited_your_post": "favorited your post", + "reblogged_your_post": "reblogged your post", + "mentioned_you": "mentioned you", + "request_to_follow_you": "request to follow you", + "poll_has_ended": "poll has ended" + }, + "keyobard": { + "show_everything": "Show Everything", + "show_mentions": "Show Mentions" + } + }, + "thread": { + "back_title": "Post", + "title": "Post from %s" + }, + "settings": { + "title": "Settings", + "section": { + "appearance": { + "title": "Appearance", + "automatic": "Automatic", + "light": "Always Light", + "dark": "Always Dark" + }, + "look_and_feel": { + "title": "Look and Feel", + "use_system": "Use System", + "really_dark": "Really Dark", + "sorta_dark": "Sorta Dark", + "light": "Light" + }, + "notifications": { + "title": "Notifications", + "favorites": "Favorites my post", + "follows": "Follows me", + "boosts": "Reblogs my post", + "mentions": "Mentions me", + "trigger": { + "anyone": "anyone", + "follower": "a follower", + "follow": "anyone I follow", + "noone": "no one", + "title": "Notify me when" + } + }, + "preference": { + "title": "Preferences", + "true_black_dark_mode": "True black dark mode", + "disable_avatar_animation": "Disable animated avatars", + "disable_emoji_animation": "Disable animated emojis", + "using_default_browser": "Use default browser to open links", + "open_links_in_mastodon": "Open links in Mastodon" + }, + "boring_zone": { + "title": "The Boring Zone", + "account_settings": "Account Settings", + "terms": "Terms of Service", + "privacy": "Privacy Policy" + }, + "spicy_zone": { + "title": "The Spicy Zone", + "clear": "Clear Media Cache", + "signout": "Sign Out" + } + }, + "footer": { + "mastodon_description": "Mastodon is open source software. You can report issues on GitHub at %s (%s)" + }, + "keyboard": { + "close_settings_window": "Close Settings Window" + } + }, + "report": { + "title_report": "Report", + "title": "Report %s", + "step1": "Step 1 of 2", + "step2": "Step 2 of 2", + "content1": "Are there any other posts you’d like to add to the report?", + "content2": "Is there anything the moderators should know about this report?", + "report_sent_title": "Thanks for reporting, we’ll look into this.", + "send": "Send Report", + "skip_to_send": "Send without comment", + "text_placeholder": "Type or paste additional comments", + "reported": "REPORTED" + }, + "preview": { + "keyboard": { + "close_preview": "Close Preview", + "show_next": "Show Next", + "show_previous": "Show Previous" + } + }, + "account_list": { + "tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher", + "dismiss_account_switcher": "Dismiss Account Switcher", + "add_account": "Add Account" + }, + "wizard": { + "new_in_mastodon": "New in Mastodon", + "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", + "accessibility_hint": "Double tap to dismiss this wizard" + } + } +} \ No newline at end of file From 0318da6ec5e24b6349e51259a2233716923ee9a9 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 04:56:14 +0200 Subject: [PATCH 078/188] New translations ios-infoPlist.json (Vietnamese) --- .../StringsConvertor/input/vi_VN/ios-infoPlist.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Localization/StringsConvertor/input/vi_VN/ios-infoPlist.json diff --git a/Localization/StringsConvertor/input/vi_VN/ios-infoPlist.json b/Localization/StringsConvertor/input/vi_VN/ios-infoPlist.json new file mode 100644 index 00000000..c6db73de --- /dev/null +++ b/Localization/StringsConvertor/input/vi_VN/ios-infoPlist.json @@ -0,0 +1,6 @@ +{ + "NSCameraUsageDescription": "Used to take photo for post status", + "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library", + "NewPostShortcutItemTitle": "New Post", + "SearchShortcutItemTitle": "Search" +} From 20f92aee37e6424ba1cba5afc446a818e99039f1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 04:56:15 +0200 Subject: [PATCH 079/188] New translations Localizable.stringsdict (Vietnamese) --- .../input/vi_VN/Localizable.stringsdict | 356 ++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 Localization/StringsConvertor/input/vi_VN/Localizable.stringsdict diff --git a/Localization/StringsConvertor/input/vi_VN/Localizable.stringsdict b/Localization/StringsConvertor/input/vi_VN/Localizable.stringsdict new file mode 100644 index 00000000..c69fd562 --- /dev/null +++ b/Localization/StringsConvertor/input/vi_VN/Localizable.stringsdict @@ -0,0 +1,356 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld unread notification + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + Input limit exceeds %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld characters + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + Input limit remains %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld characters + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + posts + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld posts + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld favorites + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld reblogs + + + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld replies + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld votes + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld voters + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld people talking + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld following + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld followers + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld years left + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld months left + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld days left + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld hours left + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld minutes left + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld seconds left + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ldy ago + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ldM ago + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ldd ago + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ldh ago + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ldm ago + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %lds ago + + + + From 2e888cfc2340d8c1e93f49ca569938f0d5ff77dc Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 04:56:16 +0200 Subject: [PATCH 080/188] New translations Intents.strings (Vietnamese) --- .../Intents/input/vi_VN/Intents.strings | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Localization/StringsConvertor/Intents/input/vi_VN/Intents.strings diff --git a/Localization/StringsConvertor/Intents/input/vi_VN/Intents.strings b/Localization/StringsConvertor/Intents/input/vi_VN/Intents.strings new file mode 100644 index 00000000..6877490b --- /dev/null +++ b/Localization/StringsConvertor/Intents/input/vi_VN/Intents.strings @@ -0,0 +1,51 @@ +"16wxgf" = "Post on Mastodon"; + +"751xkl" = "Text Content"; + +"CsR7G2" = "Post on Mastodon"; + +"HZSGTr" = "What content to post?"; + +"HdGikU" = "Posting failed"; + +"KDNTJ4" = "Failure Reason"; + +"RHxKOw" = "Send Post with text content"; + +"RxSqsb" = "Post"; + +"WCIR3D" = "Post ${content} on Mastodon"; + +"ZKJSNu" = "Post"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "Visibility"; + +"Zo4jgJ" = "Post Visibility"; + +"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; + +"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; + +"ayoYEb-dYQ5NN" = "${content}, Public"; + +"ayoYEb-ehFLjY" = "${content}, Followers Only"; + +"dUyuGg" = "Post on Mastodon"; + +"dYQ5NN" = "Public"; + +"ehFLjY" = "Followers Only"; + +"gfePDu" = "Posting failed. ${failureReason}"; + +"k7dbKQ" = "Post was sent successfully."; + +"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; + +"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; + +"rM6dvp" = "URL"; + +"ryJLwG" = "Post was sent successfully. "; From 97500ad09becc025aa439ab872186cfcd6ee702d Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 04:56:17 +0200 Subject: [PATCH 081/188] New translations Intents.stringsdict (Vietnamese) --- .../Intents/input/vi_VN/Intents.stringsdict | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Localization/StringsConvertor/Intents/input/vi_VN/Intents.stringsdict diff --git a/Localization/StringsConvertor/Intents/input/vi_VN/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/vi_VN/Intents.stringsdict new file mode 100644 index 00000000..a14f8b9f --- /dev/null +++ b/Localization/StringsConvertor/Intents/input/vi_VN/Intents.stringsdict @@ -0,0 +1,34 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${content}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + other + %ld options + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${visibility}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + other + %ld options + + + + From 83e577fa9544021464c7ba47f7db1854e33ed2f2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 07:58:36 +0200 Subject: [PATCH 082/188] New translations Localizable.stringsdict (Arabic) --- .../input/ar_SA/Localizable.stringsdict | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index 8d181e07..32782f1c 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -181,15 +181,15 @@ NSStringFormatValueTypeKey ld zero - %ld replies + لا رَدّ one - 1 reply + رَدٌّ واحِد two - %ld replies + رَدَّانِ اِثنان few - %ld replies + %ld رُدُود many - %ld replies + %ld رَدًّا other %ld رَدّ From f15e8c1f6c22b61fb3a58b57445ea96df5ae8927 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 08:54:17 +0200 Subject: [PATCH 083/188] New translations app.json (Vietnamese) --- .../StringsConvertor/input/vi_VN/app.json | 172 +++++++++--------- 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/Localization/StringsConvertor/input/vi_VN/app.json b/Localization/StringsConvertor/input/vi_VN/app.json index f0dc0ebf..fb456e91 100644 --- a/Localization/StringsConvertor/input/vi_VN/app.json +++ b/Localization/StringsConvertor/input/vi_VN/app.json @@ -2,84 +2,84 @@ "common": { "alerts": { "common": { - "please_try_again": "Please try again.", - "please_try_again_later": "Please try again later." + "please_try_again": "Vui lòng thử lại.", + "please_try_again_later": "Vui lòng thử lại sau." }, "sign_up_failure": { - "title": "Sign Up Failure" + "title": "Đăng ký không thành công" }, "server_error": { - "title": "Server Error" + "title": "Lỗi máy chủ" }, "vote_failure": { - "title": "Vote Failure", - "poll_ended": "The poll has ended" + "title": "Bình chọn không thành công", + "poll_ended": "Cuộc bình chọn đã kết thúc" }, "discard_post_content": { - "title": "Discard Draft", - "message": "Confirm to discard composed post content." + "title": "Hủy bản nháp", + "message": "Xác nhận bỏ qua nội dung tút đã viết." }, "publish_post_failure": { - "title": "Publish Failure", - "message": "Failed to publish the post.\nPlease check your internet connection.", + "title": "Đăng tút không thành công", + "message": "Không thể đăng tút.\nVui lòng kiểm tra kết nối mạng.", "attachments_message": { - "video_attach_with_photo": "Cannot attach a video to a post that already contains images.", - "more_than_one_video": "Cannot attach more than one video." + "video_attach_with_photo": "Không thể đính kèm video cùng với hình ảnh.", + "more_than_one_video": "Không thể đính kèm nhiều video." } }, "edit_profile_failure": { - "title": "Edit Profile Error", - "message": "Cannot edit profile. Please try again." + "title": "Lỗi chỉnh sửa trang cá nhân", + "message": "Không thể chỉnh sửa trang cá nhân. Vui lòng thử lại." }, "sign_out": { - "title": "Sign Out", - "message": "Are you sure you want to sign out?", - "confirm": "Sign Out" + "title": "Đăng xuất", + "message": "Bạn có chắc muốn đăng xuất không?", + "confirm": "Đăng xuất" }, "block_domain": { - "title": "Are you really, really sure you want to block the entire %s? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain and any of your followers from that domain will be removed.", - "block_entire_domain": "Block Domain" + "title": "Bạn thật sự muốn ẩn toàn bộ nội dung từ %s? Sẽ hợp lý hơn nếu bạn chỉ chặn hoặc ẩn một vài tài khoản cụ thể. Ẩn toàn bộ nội dung từ máy chủ sẽ khiến bạn không còn thấy nội dung từ máy chủ đó ở bất kỳ nơi nào, kể cả thông báo. Người theo dõi bạn từ máy chủ đó cũng sẽ bị xóa luôn.", + "block_entire_domain": "Chặn máy chủ" }, "save_photo_failure": { - "title": "Save Photo Failure", - "message": "Please enable the photo library access permission to save the photo." + "title": "Lưu hình ảnh không thành công", + "message": "Vui lòng cho phép quyền truy cập thư viện hình ảnh để lưu hình ảnh về máy." }, "delete_post": { - "title": "Delete Post", - "message": "Are you sure you want to delete this post?" + "title": "Xóa tút", + "message": "Bạn có chắc muốn xóa tút này không?" }, "clean_cache": { - "title": "Clean Cache", - "message": "Successfully cleaned %s cache." + "title": "Xóa bộ nhớ đệm", + "message": "Đã xóa %s bộ nhớ đệm." } }, "controls": { "actions": { - "back": "Back", - "next": "Next", - "previous": "Previous", - "open": "Open", - "add": "Add", - "remove": "Remove", - "edit": "Edit", - "save": "Save", + "back": "Quay lại", + "next": "Kế tiếp", + "previous": "Trước đó", + "open": "Mở", + "add": "Thêm", + "remove": "Xóa", + "edit": "Sửa", + "save": "Lưu", "ok": "OK", - "done": "Done", - "confirm": "Confirm", - "continue": "Continue", - "compose": "Compose", - "cancel": "Cancel", - "discard": "Discard", - "try_again": "Try Again", - "take_photo": "Take Photo", - "save_photo": "Save Photo", - "copy_photo": "Copy Photo", - "sign_in": "Sign In", - "sign_up": "Sign Up", - "see_more": "See More", - "preview": "Preview", - "share": "Share", - "share_user": "Share %s", + "done": "Xong", + "confirm": "Xác nhận", + "continue": "Tiếp tục", + "compose": "Viết tút", + "cancel": "Hủy bỏ", + "discard": "Bỏ qua", + "try_again": "Thử lại", + "take_photo": "Chụp ảnh", + "save_photo": "Lưu ảnh", + "copy_photo": "Sao chép ảnh", + "sign_in": "Đăng nhập", + "sign_up": "Đăng ký", + "see_more": "Xem thêm", + "preview": "Xem trước", + "share": "Chia sẻ", + "share_user": "Chia sẻ %s", "share_post": "Share Post", "open_in_safari": "Open in Safari", "open_in_browser": "Open in Browser", @@ -145,67 +145,67 @@ "hide": "Hide", "show_image": "Show image", "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_video_player": "Hiện trình phát video", + "tap_then_hold_to_show_menu": "Nhấn giữ để hiện menu" }, "tag": { "url": "URL", - "mention": "Mention", - "link": "Link", + "mention": "Nhắc đến", + "link": "Liên kết", "hashtag": "Hashtag", "email": "Email", "emoji": "Emoji" }, "visibility": { - "unlisted": "Everyone can see this post but not display in the public timeline.", - "private": "Only their followers can see this post.", - "private_from_me": "Only my followers can see this post.", - "direct": "Only mentioned user can see this post." + "unlisted": "Ai cũng thấy tút này nhưng không hiện trên bảng tin máy chủ.", + "private": "Chỉ người theo dõi của họ có thể thấy tút này.", + "private_from_me": "Chỉ người theo dõi tôi có thể thấy tút này.", + "direct": "Chỉ người được nhắc đến có thể thấy tút." } }, "friendship": { - "follow": "Follow", - "following": "Following", - "request": "Request", - "pending": "Pending", - "block": "Block", - "block_user": "Block %s", - "block_domain": "Block %s", - "unblock": "Unblock", - "unblock_user": "Unblock %s", - "blocked": "Blocked", - "mute": "Mute", - "mute_user": "Mute %s", - "unmute": "Unmute", - "unmute_user": "Unmute %s", - "muted": "Muted", - "edit_info": "Edit Info" + "follow": "Theo dõi", + "following": "Đang theo dõi", + "request": "Yêu cầu", + "pending": "Đang chờ", + "block": "Chặn", + "block_user": "Chặn %s", + "block_domain": "Chặn %s", + "unblock": "Bỏ chặn", + "unblock_user": "Bỏ chặn %s", + "blocked": "Đã chặn", + "mute": "Ẩn", + "mute_user": "Ẩn %s", + "unmute": "Bỏ ẩn", + "unmute_user": "Bỏ ẩn %s", + "muted": "Đã ẩn", + "edit_info": "Chỉnh sửa" }, "timeline": { - "filtered": "Filtered", + "filtered": "Bộ lọc", "timestamp": { - "now": "Now" + "now": "Vừa xong" }, "loader": { - "load_missing_posts": "Load missing posts", - "loading_missing_posts": "Loading missing posts...", - "show_more_replies": "Show more replies" + "load_missing_posts": "Tải tút chưa đọc", + "loading_missing_posts": "Đang tải tút chưa đọc...", + "show_more_replies": "Xem lượt trả lời" }, "header": { - "no_status_found": "No Post Found", - "blocking_warning": "You can’t view this user's profile\nuntil you unblock them.\nYour profile looks like this to them.", - "user_blocking_warning": "You can’t view %s’s profile\nuntil you unblock them.\nYour profile looks like this to them.", - "blocked_warning": "You can’t view this user’s profile\nuntil they unblock you.", - "user_blocked_warning": "You can’t view %s’s profile\nuntil they unblock you.", - "suspended_warning": "This user has been suspended.", - "user_suspended_warning": "%s’s account has been suspended." + "no_status_found": "Không tìm thấy tút", + "blocking_warning": "Bạn không thể xem trang người này\ncho tới khi bạn bỏ chặn họ.\nHọ sẽ thấy trang của bạn như thế này.", + "user_blocking_warning": "Bạn không thể xem trang %s\ncho tới khi bạn bỏ chặn họ.\nHọ sẽ thấy trang của bạn như thế này.", + "blocked_warning": "Bạn không thể xem trang người này\ncho tới khi họ bỏ chặn bạn.", + "user_blocked_warning": "Bạn không thể xem trang %s\ncho tới khi họ bỏ chặn bạn.", + "suspended_warning": "Người dùng đã bị vô hiệu hóa.", + "user_suspended_warning": "%s đã bị vô hiệu hóa." } } } }, "scene": { "welcome": { - "slogan": "Social networking\nback in your hands.", + "slogan": "Mạng xã hội\ndo bạn kiểm soát.", "get_started": "Get Started", "log_in": "Log In" }, From 25fd74632a7de2b27241b411dfb70a423e5d863a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 10:03:45 +0200 Subject: [PATCH 084/188] New translations app.json (Vietnamese) --- .../StringsConvertor/input/vi_VN/app.json | 398 +++++++++--------- 1 file changed, 199 insertions(+), 199 deletions(-) diff --git a/Localization/StringsConvertor/input/vi_VN/app.json b/Localization/StringsConvertor/input/vi_VN/app.json index fb456e91..f27ce883 100644 --- a/Localization/StringsConvertor/input/vi_VN/app.json +++ b/Localization/StringsConvertor/input/vi_VN/app.json @@ -80,71 +80,71 @@ "preview": "Xem trước", "share": "Chia sẻ", "share_user": "Chia sẻ %s", - "share_post": "Share Post", - "open_in_safari": "Open in Safari", - "open_in_browser": "Open in Browser", - "find_people": "Find people to follow", - "manually_search": "Manually search instead", - "skip": "Skip", - "reply": "Reply", - "report_user": "Report %s", - "block_domain": "Block %s", - "unblock_domain": "Unblock %s", - "settings": "Settings", - "delete": "Delete" + "share_post": "Chia sẻ tút", + "open_in_safari": "Mở bằng Safari", + "open_in_browser": "Mở trong trình duyệt", + "find_people": "Đề xuất theo dõi", + "manually_search": "Tự tìm kiếm thủ công", + "skip": "Bỏ qua", + "reply": "Trả lời", + "report_user": "Báo cáo %s", + "block_domain": "Chặn %s", + "unblock_domain": "Bỏ chặn %s", + "settings": "Cài đặt", + "delete": "Xóa" }, "tabs": { - "home": "Home", - "search": "Search", - "notification": "Notification", - "profile": "Profile" + "home": "Bảng tin", + "search": "Tìm kiếm", + "notification": "Thông báo", + "profile": "Trang cá nhân" }, "keyboard": { "common": { - "switch_to_tab": "Switch to %s", - "compose_new_post": "Compose New Post", - "show_favorites": "Show Favorites", - "open_settings": "Open Settings" + "switch_to_tab": "Chuyển thành %s", + "compose_new_post": "Viết tút mới", + "show_favorites": "Hiện lượt thích", + "open_settings": "Mở cài đặt" }, "timeline": { - "previous_status": "Previous Post", - "next_status": "Next Post", - "open_status": "Open Post", - "open_author_profile": "Open Author's Profile", - "open_reblogger_profile": "Open Reblogger's Profile", - "reply_status": "Reply to Post", - "toggle_reblog": "Toggle Reblog on Post", - "toggle_favorite": "Toggle Favorite on Post", - "toggle_content_warning": "Toggle Content Warning", - "preview_image": "Preview Image" + "previous_status": "Tút trước", + "next_status": "Tút sau", + "open_status": "Mở tút", + "open_author_profile": "Mở trang người viết tút", + "open_reblogger_profile": "Mở trang người đăng lại tút", + "reply_status": "Trả lời tút", + "toggle_reblog": "Chọn đăng lại tút", + "toggle_favorite": "Chọn thích tút", + "toggle_content_warning": "Chọn nội dung ẩn", + "preview_image": "Xem trước hình ảnh" }, "segmented_control": { - "previous_section": "Previous Section", - "next_section": "Next Section" + "previous_section": "Tới phần trước", + "next_section": "Tới phần tiếp theo" } }, "status": { - "user_reblogged": "%s reblogged", - "user_replied_to": "Replied to %s", - "show_post": "Show Post", - "show_user_profile": "Show user profile", - "content_warning": "Content Warning", - "media_content_warning": "Tap anywhere to reveal", - "tap_to_reveal": "Tap to reveal", + "user_reblogged": "%s đăng lại", + "user_replied_to": "Trả lời %s", + "show_post": "Xem tút", + "show_user_profile": "Xem trang cá nhân", + "content_warning": "Nội dung ẩn", + "media_content_warning": "Nhấn để hiển thị", + "tap_to_reveal": "Nhấn để hiển thị", "poll": { - "vote": "Vote", - "closed": "Closed" + "vote": "Bình chọn", + "closed": "Kết thúc" }, "actions": { - "reply": "Reply", - "reblog": "Reblog", - "unreblog": "Undo reblog", - "favorite": "Favorite", - "unfavorite": "Unfavorite", + "reply": "Trả lời", + "reblog": "Đăng lại", + "unreblog": "Hủy đăng lại", + "favorite": "Thích", + "unfavorite": "Bỏ thích", "menu": "Menu", - "hide": "Hide", - "show_image": "Show image", - "show_gif": "Show GIF", + "hide": "Ẩn", + "show_image": "Hiển thị hình ảnh", + "show_gif": "Hiển thị GIF", "show_video_player": "Hiện trình phát video", "tap_then_hold_to_show_menu": "Nhấn giữ để hiện menu" }, @@ -206,219 +206,219 @@ "scene": { "welcome": { "slogan": "Mạng xã hội\ndo bạn kiểm soát.", - "get_started": "Get Started", - "log_in": "Log In" + "get_started": "Bắt đầu", + "log_in": "Đăng nhập" }, "server_picker": { - "title": "Mastodon is made of users in different communities.", - "subtitle": "Pick a community based on your interests, region, or a general purpose one.", - "subtitle_extend": "Pick a community based on your interests, region, or a general purpose one. Each community is operated by an entirely independent organization or individual.", + "title": "Mastodon gồm nhiều cộng đồng với nhiều thành viên khác nhau.", + "subtitle": "Chọn một cộng đồng dựa theo sở thích, tôn giáo, hoặc ý muốn của bạn.", + "subtitle_extend": "Chọn một cộng đồng dựa theo sở thích, tôn giáo, hoặc ý muốn của bạn. Mỗi cộng đồng có thể được vận hành bởi một tổ chức độc lập hoặc một cá nhân.", "button": { "category": { - "all": "All", - "all_accessiblity_description": "Category: All", - "academia": "academia", - "activism": "activism", - "food": "food", + "all": "Toàn bộ", + "all_accessiblity_description": "Phân loại: Toàn bộ", + "academia": "học thuật", + "activism": "hoạt động xã hội", + "food": "ăn uống", "furry": "furry", - "games": "games", - "general": "general", - "journalism": "journalism", + "games": "trò chơi", + "general": "chung", + "journalism": "tin tức", "lgbt": "lgbt", - "regional": "regional", - "art": "art", - "music": "music", - "tech": "tech" + "regional": "khu vực", + "art": "nghệ thuật", + "music": "âm nhạc", + "tech": "công nghệ" }, - "see_less": "See Less", - "see_more": "See More" + "see_less": "Ẩn bớt", + "see_more": "Nhiều hơn" }, "label": { - "language": "LANGUAGE", - "users": "USERS", - "category": "CATEGORY" + "language": "NGÔN NGỮ", + "users": "NGƯỜI DÙNG", + "category": "PHÂN LOẠI" }, "input": { - "placeholder": "Search communities" + "placeholder": "Tìm cộng đồng" }, "empty_state": { - "finding_servers": "Finding available servers...", - "bad_network": "Something went wrong while loading the data. Check your internet connection.", - "no_results": "No results" + "finding_servers": "Đang tìm máy chủ hoạt động...", + "bad_network": "Đã xảy ra lỗi. Hãy thử lại hoặc kiểm tra kết nối internet của bạn.", + "no_results": "Không có kết quả" } }, "register": { - "title": "Let’s get you set up on %s", + "title": "Hãy để tôi đăng ký trên %s", "input": { "avatar": { - "delete": "Delete" + "delete": "Xóa" }, "username": { - "placeholder": "username", - "duplicate_prompt": "This username is taken." + "placeholder": "tên người dùng", + "duplicate_prompt": "Tên người dùng đã tồn tại." }, "display_name": { - "placeholder": "display name" + "placeholder": "tên hiển thị" }, "email": { "placeholder": "email" }, "password": { - "placeholder": "password", - "require": "Your password needs at least:", - "character_limit": "8 characters", + "placeholder": "mật khẩu", + "require": "Mật khẩu phải tối thiểu:", + "character_limit": "8 ký tự", "accessibility": { - "checked": "checked", - "unchecked": "unchecked" + "checked": "đã ổn", + "unchecked": "chưa ổn" }, - "hint": "Your password needs at least eight characters" + "hint": "Mật khẩu của bạn phải dài tối thiểu 8 ký tự" }, "invite": { - "registration_user_invite_request": "Why do you want to join?" + "registration_user_invite_request": "Vì sao bạn muốn tham gia?" } }, "error": { "item": { - "username": "Username", + "username": "Tên người dùng", "email": "Email", - "password": "Password", - "agreement": "Agreement", - "locale": "Locale", - "reason": "Reason" + "password": "Mật khẩu", + "agreement": "Thoả thuận", + "locale": "Cục bộ", + "reason": "Lý do" }, "reason": { - "blocked": "%s contains a disallowed email provider", - "unreachable": "%s does not seem to exist", - "taken": "%s is already in use", - "reserved": "%s is a reserved keyword", - "accepted": "%s must be accepted", - "blank": "%s is required", - "invalid": "%s is invalid", - "too_long": "%s is too long", - "too_short": "%s is too short", - "inclusion": "%s is not a supported value" + "blocked": "%s dùng dịch vụ email bị cấm", + "unreachable": "%s không tồn tại", + "taken": "%s đã tồn tại", + "reserved": "%s là một từ khóa hạn chế", + "accepted": "%s phải được đồng ý", + "blank": "%s là bắt buộc", + "invalid": "%s không hợp lệ", + "too_long": "%s quá dài", + "too_short": "%s quá ngắn", + "inclusion": "%s chứa ký tự không được hỗ trợ" }, "special": { - "username_invalid": "Username must only contain alphanumeric characters and underscores", - "username_too_long": "Username is too long (can’t be longer than 30 characters)", - "email_invalid": "This is not a valid email address", - "password_too_short": "Password is too short (must be at least 8 characters)" + "username_invalid": "Tên người dùng chỉ có thể chứa các ký tự chữ và số và dấu gạch dưới", + "username_too_long": "Tên người dùng không thể dài hơn 30 ký tự", + "email_invalid": "Đây không phải là một địa chỉ email khả dụng", + "password_too_short": "Mật khẩu của bạn quá ngắn, phải có ít nhất 8 ký tự" } } }, "server_rules": { - "title": "Some ground rules.", - "subtitle": "These are set and enforced by the %s moderators.", - "prompt": "By continuing, you’re subject to the terms of service and privacy policy for %s.", - "terms_of_service": "terms of service", - "privacy_policy": "privacy policy", + "title": "Quy tắc máy chủ.", + "subtitle": "Được ban hành và áp dụng bởi quản trị viên %s", + "prompt": "Tiếp tục nghĩa là bạn đồng ý điều khoản dịch vụ và chính sách bảo mật của %s.", + "terms_of_service": "điều khoản dịch vụ", + "privacy_policy": "chính sách bảo mật", "button": { - "confirm": "I Agree" + "confirm": "Tôi đồng ý" } }, "confirm_email": { - "title": "One last thing.", - "subtitle": "Tap the link we emailed to you to verify your account.", + "title": "Còn điều này nữa.", + "subtitle": "Nhấn vào liên kết chúng tôi gửi qua email để xác thực tài khoản.", "button": { - "open_email_app": "Open Email App", - "resend": "Resend" + "open_email_app": "Mở ứng dụng email", + "resend": "Gửi lại" }, "dont_receive_email": { - "title": "Check your email", - "description": "Check if your email address is correct as well as your junk folder if you haven’t.", - "resend_email": "Resend Email" + "title": "Kiểm tra email", + "description": "Kiểm tra địa chỉ email của bạn đúng chưa hoặc có bị chuyển vào thư rác.", + "resend_email": "Gửi lại email" }, "open_email_app": { - "title": "Check your inbox.", - "description": "We just sent you an email. Check your junk folder if you haven’t.", - "mail": "Mail", - "open_email_client": "Open Email Client" + "title": "Kiểm tra hộp thư của bạn.", + "description": "Chúng tôi vừa gửi email cho bạn. Kiểm tra thư rác nếu bạn không thấy.", + "mail": "Email", + "open_email_client": "Mở ứng dụng email" } }, "home_timeline": { - "title": "Home", + "title": "Bảng tin", "navigation_bar_state": { - "offline": "Offline", - "new_posts": "See new posts", - "published": "Published!", - "Publishing": "Publishing post..." + "offline": "Ngoại tuyến", + "new_posts": "Đọc những tút mới", + "published": "Đã đăng!", + "Publishing": "Đang đăng tút..." } }, "suggestion_account": { - "title": "Find People to Follow", - "follow_explain": "When you follow someone, you’ll see their posts in your home feed." + "title": "Đề xuất theo dõi", + "follow_explain": "Khi theo dõi ai đó, bạn sẽ thấy tút của họ trong bảng tin." }, "compose": { "title": { - "new_post": "New Post", - "new_reply": "New Reply" + "new_post": "Viết tút", + "new_reply": "Viết trả lời" }, "media_selection": { - "camera": "Take Photo", - "photo_library": "Photo Library", - "browse": "Browse" + "camera": "Chụp ảnh", + "photo_library": "Thư viện hình ảnh", + "browse": "Chọn" }, - "content_input_placeholder": "Type or paste what’s on your mind", - "compose_action": "Publish", - "replying_to_user": "replying to %s", + "content_input_placeholder": "Cho thế giới biết bạn đang nghĩ gì", + "compose_action": "Đăng", + "replying_to_user": "trả lời đến %s", "attachment": { - "photo": "photo", + "photo": "ảnh", "video": "video", - "attachment_broken": "This %s is broken and can’t be\nuploaded to Mastodon.", - "description_photo": "Describe the photo for the visually-impaired...", - "description_video": "Describe the video for the visually-impaired..." + "attachment_broken": "%s này bị lỗi và không thể\ntải lên Mastodon.", + "description_photo": "Mô tả hình ảnh cho người khiếm thị...", + "description_video": "Mô tả video cho người khiếm thị..." }, "poll": { - "duration_time": "Duration: %s", - "thirty_minutes": "30 minutes", - "one_hour": "1 Hour", - "six_hours": "6 Hours", - "one_day": "1 Day", - "three_days": "3 Days", - "seven_days": "7 Days", - "option_number": "Option %ld" + "duration_time": "Thời gian: %s", + "thirty_minutes": "30 phút", + "one_hour": "1 giờ", + "six_hours": "6 giờ", + "one_day": "1 ngày", + "three_days": "3 ngày", + "seven_days": "7 ngày", + "option_number": "Lựa chọn %ld" }, "content_warning": { - "placeholder": "Write an accurate warning here..." + "placeholder": "Viết nội dung ẩn của bạn ở đây..." }, "visibility": { - "public": "Public", - "unlisted": "Unlisted", - "private": "Followers only", - "direct": "Only people I mention" + "public": "Công khai", + "unlisted": "Hạn chế", + "private": "Riêng tư", + "direct": "Chỉ người được nhắc đến" }, "auto_complete": { - "space_to_add": "Space to add" + "space_to_add": "Khoảng cách để thêm" }, "accessibility": { - "append_attachment": "Add Attachment", - "append_poll": "Add Poll", - "remove_poll": "Remove Poll", - "custom_emoji_picker": "Custom Emoji Picker", - "enable_content_warning": "Enable Content Warning", - "disable_content_warning": "Disable Content Warning", - "post_visibility_menu": "Post Visibility Menu" + "append_attachment": "Thêm media", + "append_poll": "Tạo bình chọn", + "remove_poll": "Xóa bình chọn", + "custom_emoji_picker": "Chọn emoji", + "enable_content_warning": "Bật nội dung ẩn", + "disable_content_warning": "Tắt nội dung ẩn", + "post_visibility_menu": "Menu hiển thị tút" }, "keyboard": { - "discard_post": "Discard Post", - "publish_post": "Publish Post", - "toggle_poll": "Toggle Poll", - "toggle_content_warning": "Toggle Content Warning", - "append_attachment_entry": "Add Attachment - %s", - "select_visibility_entry": "Select Visibility - %s" + "discard_post": "Hủy đăng tút", + "publish_post": "Đăng tút", + "toggle_poll": "Mở bình chọn", + "toggle_content_warning": "Mở nội dung ẩn", + "append_attachment_entry": "Thêm media - %s", + "select_visibility_entry": "Thay đổi quyền riêng tư - %s" } }, "profile": { "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "posts": "tút", + "following": "theo dõi", + "followers": "người theo dõi" }, "fields": { - "add_row": "Add Row", + "add_row": "Thêm hàng", "placeholder": { - "label": "Label", - "content": "Content" + "label": "Nhãn", + "content": "Nội dung" } }, "segmented_control": { @@ -449,56 +449,56 @@ "accessibility": { "show_avatar_image": "Show avatar image", "edit_avatar_image": "Edit avatar image", - "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "show_banner_image": "Hiển thị ảnh bìa", + "double_tap_to_open_the_list": "Nhấn hai lần để mở danh sách" } }, "follower": { - "footer": "Followers from other servers are not displayed." + "footer": "Không hiển thị người theo dõi từ máy chủ khác." }, "following": { - "footer": "Follows from other servers are not displayed." + "footer": "Không hiển thị người bạn theo dõi từ máy chủ khác." }, "search": { - "title": "Search", + "title": "Tìm kiếm", "search_bar": { - "placeholder": "Search hashtags and users", - "cancel": "Cancel" + "placeholder": "Tìm hashtag và người dùng", + "cancel": "Hủy bỏ" }, "recommend": { - "button_text": "See All", + "button_text": "Xem tất cả", "hash_tag": { - "title": "Trending on Mastodon", - "description": "Hashtags that are getting quite a bit of attention", - "people_talking": "%s people are talking" + "title": "Xu hướng trên Mastodon", + "description": "Những hashtag đang được sử dụng nhiều nhất", + "people_talking": "%s người đang thảo luận" }, "accounts": { - "title": "Accounts you might like", - "description": "You may like to follow these accounts", - "follow": "Follow" + "title": "Những người bạn có thể thích", + "description": "Bạn có thể muốn theo dõi những người này", + "follow": "Theo dõi" } }, "searching": { "segment": { - "all": "All", - "people": "People", - "hashtags": "Hashtags", - "posts": "Posts" + "all": "Tất cả", + "people": "Người dùng", + "hashtags": "Hashtag", + "posts": "Tút" }, "empty_state": { - "no_results": "No results" + "no_results": "Không có kết quả" }, - "recent_search": "Recent searches", - "clear": "Clear" + "recent_search": "Tìm kiếm gần đây", + "clear": "Xóa" } }, "favorite": { - "title": "Your Favorites" + "title": "Lượt thích" }, "notification": { "title": { - "Everything": "Everything", - "Mentions": "Mentions" + "Everything": "Mọi thứ", + "Mentions": "Lượt nhắc đến" }, "notification_description": { "followed_you": "followed you", From e2942e0128ba38c2faa2331ac5c6c88fcec1a542 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 11:56:10 +0200 Subject: [PATCH 085/188] New translations app.json (Vietnamese) --- .../StringsConvertor/input/vi_VN/app.json | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Localization/StringsConvertor/input/vi_VN/app.json b/Localization/StringsConvertor/input/vi_VN/app.json index f27ce883..e6e7a00e 100644 --- a/Localization/StringsConvertor/input/vi_VN/app.json +++ b/Localization/StringsConvertor/input/vi_VN/app.json @@ -422,33 +422,33 @@ } }, "segmented_control": { - "posts": "Posts", - "replies": "Replies", - "posts_and_replies": "Posts and Replies", + "posts": "Tút", + "replies": "Trả lời", + "posts_and_replies": "Tút và trả lời", "media": "Media", - "about": "About" + "about": "Giới thiệu" }, "relationship_action_alert": { "confirm_mute_user": { - "title": "Mute Account", - "message": "Confirm to mute %s" + "title": "Ẩn người dùng", + "message": "Xác nhận ẩn %s" }, "confirm_unmute_user": { - "title": "Unmute Account", - "message": "Confirm to unmute %s" + "title": "Bỏ ẩn người dùng", + "message": "Xác nhận bỏ ẩn %s" }, "confirm_block_user": { - "title": "Block Account", - "message": "Confirm to block %s" + "title": "Chặn người dùng", + "message": "Xác nhận chặn %s" }, "confirm_unblock_user": { - "title": "Unblock Account", - "message": "Confirm to unblock %s" + "title": "Bỏ chặn người dùng", + "message": "Xác nhận bỏ chặn %s" } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", + "show_avatar_image": "Hiển thị ảnh đại diện", + "edit_avatar_image": "Sửa ảnh đại diện", "show_banner_image": "Hiển thị ảnh bìa", "double_tap_to_open_the_list": "Nhấn hai lần để mở danh sách" } From 9f69113ca804d12800d68a5161394e3285366fa9 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 12:51:53 +0200 Subject: [PATCH 086/188] New translations app.json (Italian) --- .../StringsConvertor/input/it_IT/app.json | 118 +++++++++--------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/app.json b/Localization/StringsConvertor/input/it_IT/app.json index f0dc0ebf..03fc64e3 100644 --- a/Localization/StringsConvertor/input/it_IT/app.json +++ b/Localization/StringsConvertor/input/it_IT/app.json @@ -2,84 +2,84 @@ "common": { "alerts": { "common": { - "please_try_again": "Please try again.", - "please_try_again_later": "Please try again later." + "please_try_again": "Per favore riprova.", + "please_try_again_later": "Per favore, riprova più tardi." }, "sign_up_failure": { - "title": "Sign Up Failure" + "title": "Iscrizione fallita" }, "server_error": { - "title": "Server Error" + "title": "Errore del server" }, "vote_failure": { - "title": "Vote Failure", - "poll_ended": "The poll has ended" + "title": "Voto fallito", + "poll_ended": "Il sondaggio è terminato" }, "discard_post_content": { - "title": "Discard Draft", - "message": "Confirm to discard composed post content." + "title": "Elimina bozza", + "message": "Confermare di scartare il contenuto del post composto." }, "publish_post_failure": { - "title": "Publish Failure", - "message": "Failed to publish the post.\nPlease check your internet connection.", + "title": "Pubblicazione fallita", + "message": "Pubblicazione del post fallita.\nPer favore verifica la tua connessione internet.", "attachments_message": { - "video_attach_with_photo": "Cannot attach a video to a post that already contains images.", - "more_than_one_video": "Cannot attach more than one video." + "video_attach_with_photo": "Impossibile allegare un filmato a un post che contiene già immagini.", + "more_than_one_video": "Impossibile allegare più di un filmato." } }, "edit_profile_failure": { - "title": "Edit Profile Error", - "message": "Cannot edit profile. Please try again." + "title": "Errore nella modifica del profilo", + "message": "Impossibile modificare il profilo. Per favore, riprova." }, "sign_out": { - "title": "Sign Out", - "message": "Are you sure you want to sign out?", - "confirm": "Sign Out" + "title": "Esci", + "message": "Vuoi davvero scollegarti?", + "confirm": "Esci" }, "block_domain": { - "title": "Are you really, really sure you want to block the entire %s? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain and any of your followers from that domain will be removed.", - "block_entire_domain": "Block Domain" + "title": "Vuoi davvero bloccare %s completamente? Nella maggioranza dei casi, è preferibile e sufficiente bloccare o silenziare pochi account in modo mirato. Non vedrai i contenuti di quel dominio e tutti i tuoi follower da quel dominio verranno rimossi.", + "block_entire_domain": "Blocca il dominio" }, "save_photo_failure": { - "title": "Save Photo Failure", - "message": "Please enable the photo library access permission to save the photo." + "title": "Salvataggio foto fallito", + "message": "Si prega di abilitare l'autorizzazione di accesso alla galleria immagini per salvare la foto." }, "delete_post": { - "title": "Delete Post", - "message": "Are you sure you want to delete this post?" + "title": "Cancella il post", + "message": "Vuoi veramente eliminare questo post?" }, "clean_cache": { - "title": "Clean Cache", - "message": "Successfully cleaned %s cache." + "title": "Pulisci la cache", + "message": "Cache %s pulita con successo." } }, "controls": { "actions": { - "back": "Back", - "next": "Next", - "previous": "Previous", - "open": "Open", - "add": "Add", - "remove": "Remove", - "edit": "Edit", - "save": "Save", + "back": "Indietro", + "next": "Avanti", + "previous": "Precedente", + "open": "Apri", + "add": "Aggiungi", + "remove": "Rimuovi", + "edit": "Modifica", + "save": "Salva", "ok": "OK", - "done": "Done", - "confirm": "Confirm", - "continue": "Continue", - "compose": "Compose", - "cancel": "Cancel", - "discard": "Discard", - "try_again": "Try Again", - "take_photo": "Take Photo", - "save_photo": "Save Photo", - "copy_photo": "Copy Photo", - "sign_in": "Sign In", - "sign_up": "Sign Up", - "see_more": "See More", - "preview": "Preview", - "share": "Share", - "share_user": "Share %s", + "done": "Fatto", + "confirm": "Conferma", + "continue": "Continua", + "compose": "Scrivi", + "cancel": "Annulla", + "discard": "Abbandona", + "try_again": "Riprova", + "take_photo": "Scatta foto", + "save_photo": "Salva foto", + "copy_photo": "Copia foto", + "sign_in": "Accedi", + "sign_up": "Registrati", + "see_more": "Visualizza altro", + "preview": "Anteprima", + "share": "Condividi", + "share_user": "Condividi %s", "share_post": "Share Post", "open_in_safari": "Open in Safari", "open_in_browser": "Open in Browser", @@ -145,26 +145,26 @@ "hide": "Hide", "show_image": "Show image", "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_video_player": "Mostra lettore video", + "tap_then_hold_to_show_menu": "Tocca quindi tieni premuto per mostrare il menu" }, "tag": { "url": "URL", - "mention": "Mention", - "link": "Link", - "hashtag": "Hashtag", + "mention": "Menzione", + "link": "Collegamento", + "hashtag": "Etichetta", "email": "Email", "emoji": "Emoji" }, "visibility": { - "unlisted": "Everyone can see this post but not display in the public timeline.", - "private": "Only their followers can see this post.", - "private_from_me": "Only my followers can see this post.", - "direct": "Only mentioned user can see this post." + "unlisted": "Tutti possono vedere questo post ma non mostrare nella cronologia pubblica.", + "private": "Solo i loro seguaci possono vedere questo post.", + "private_from_me": "Solo i miei seguaci possono vedere questo post.", + "direct": "Solo l'utente menzionato può vedere questo post." } }, "friendship": { - "follow": "Follow", + "follow": "Segui", "following": "Following", "request": "Request", "pending": "Pending", From 35ef09f49d35cc3f5f834f68c2c6da2b74cf135c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 13:54:48 +0200 Subject: [PATCH 087/188] New translations app.json (Italian) --- .../StringsConvertor/input/it_IT/app.json | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/app.json b/Localization/StringsConvertor/input/it_IT/app.json index 03fc64e3..841840ec 100644 --- a/Localization/StringsConvertor/input/it_IT/app.json +++ b/Localization/StringsConvertor/input/it_IT/app.json @@ -165,60 +165,60 @@ }, "friendship": { "follow": "Segui", - "following": "Following", - "request": "Request", - "pending": "Pending", - "block": "Block", - "block_user": "Block %s", - "block_domain": "Block %s", - "unblock": "Unblock", - "unblock_user": "Unblock %s", - "blocked": "Blocked", - "mute": "Mute", - "mute_user": "Mute %s", - "unmute": "Unmute", - "unmute_user": "Unmute %s", - "muted": "Muted", - "edit_info": "Edit Info" + "following": "Stai seguendo", + "request": "Richiesta", + "pending": "In attesa", + "block": "Blocca", + "block_user": "Blocca %s", + "block_domain": "Blocca %s", + "unblock": "Sblocca", + "unblock_user": "Sblocca %s", + "blocked": "Bloccato", + "mute": "Silenzia", + "mute_user": "Silenzia %s", + "unmute": "Riattiva", + "unmute_user": "Riattiva %s", + "muted": "Silenziato", + "edit_info": "Modifica info" }, "timeline": { - "filtered": "Filtered", + "filtered": "Filtrato", "timestamp": { - "now": "Now" + "now": "Ora" }, "loader": { - "load_missing_posts": "Load missing posts", - "loading_missing_posts": "Loading missing posts...", - "show_more_replies": "Show more replies" + "load_missing_posts": "Carica i post mancanti", + "loading_missing_posts": "Caricamento post mancanti...", + "show_more_replies": "Mostra più risposte" }, "header": { - "no_status_found": "No Post Found", - "blocking_warning": "You can’t view this user's profile\nuntil you unblock them.\nYour profile looks like this to them.", - "user_blocking_warning": "You can’t view %s’s profile\nuntil you unblock them.\nYour profile looks like this to them.", - "blocked_warning": "You can’t view this user’s profile\nuntil they unblock you.", - "user_blocked_warning": "You can’t view %s’s profile\nuntil they unblock you.", - "suspended_warning": "This user has been suspended.", - "user_suspended_warning": "%s’s account has been suspended." + "no_status_found": "Nessun post trovato", + "blocking_warning": "Non puoi visualizzare il profilo di questo utente\nfinché non li sblocchi.\nIl tuo profilo sembra questo per loro.", + "user_blocking_warning": "Non puoi visualizzare il profilo di %s\nfinché non li sblocchi.\nIl tuo profilo sembra questo per loro.", + "blocked_warning": "Non puoi visualizzare il profilo di questo utente\nfino a quando non ti sbloccano.", + "user_blocked_warning": "Non puoi visualizzare il profilo di %s\nfino a quando non ti sbloccano.", + "suspended_warning": "Questo utente è stato sospeso.", + "user_suspended_warning": "L'account di %s è stato sospeso." } } } }, "scene": { "welcome": { - "slogan": "Social networking\nback in your hands.", - "get_started": "Get Started", - "log_in": "Log In" + "slogan": "Il social network, di nuovo nelle tue mani.", + "get_started": "Inizia", + "log_in": "Accedi" }, "server_picker": { - "title": "Mastodon is made of users in different communities.", - "subtitle": "Pick a community based on your interests, region, or a general purpose one.", - "subtitle_extend": "Pick a community based on your interests, region, or a general purpose one. Each community is operated by an entirely independent organization or individual.", + "title": "Mastodon è fatto di utenti in diverse comunità.", + "subtitle": "Scegli una comunità basata sui tuoi interessi, regione o uno scopo generale.", + "subtitle_extend": "Scegli una comunità basata sui tuoi interessi, regione o uno scopo generale. Ogni comunità è gestita da un'organizzazione completamente indipendente o individuale.", "button": { "category": { - "all": "All", - "all_accessiblity_description": "Category: All", - "academia": "academia", - "activism": "activism", + "all": "Tutti", + "all_accessiblity_description": "Categoria: Tutti", + "academia": "accademia", + "activism": "attivismo", "food": "food", "furry": "furry", "games": "games", @@ -301,30 +301,30 @@ "special": { "username_invalid": "Username must only contain alphanumeric characters and underscores", "username_too_long": "Username is too long (can’t be longer than 30 characters)", - "email_invalid": "This is not a valid email address", - "password_too_short": "Password is too short (must be at least 8 characters)" + "email_invalid": "Questo non è un indirizzo email valido", + "password_too_short": "La password è troppo corta (deve contenere almeno 8 caratteri)" } } }, "server_rules": { - "title": "Some ground rules.", - "subtitle": "These are set and enforced by the %s moderators.", - "prompt": "By continuing, you’re subject to the terms of service and privacy policy for %s.", - "terms_of_service": "terms of service", + "title": "Alcune regole di base.", + "subtitle": "Questi sono impostati e applicati dai moderatori %s.", + "prompt": "Continuando, sei soggetto alle condizioni di servizio e all'informativa sulla privacy per %s.", + "terms_of_service": "condizioni del servizio", "privacy_policy": "privacy policy", "button": { - "confirm": "I Agree" + "confirm": "Accetto" } }, "confirm_email": { - "title": "One last thing.", - "subtitle": "Tap the link we emailed to you to verify your account.", + "title": "Un'ultima cosa.", + "subtitle": "Tocca il link che ti abbiamo inviato per verificare il tuo account.", "button": { - "open_email_app": "Open Email App", - "resend": "Resend" + "open_email_app": "Apri l'app Email", + "resend": "Invia di nuovo" }, "dont_receive_email": { - "title": "Check your email", + "title": "Controlla la tua e-mail", "description": "Check if your email address is correct as well as your junk folder if you haven’t.", "resend_email": "Resend Email" }, From 5b1d70919172273a48e30a4939210a3c040dd39f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 14:54:36 +0200 Subject: [PATCH 088/188] New translations app.json (Italian) --- .../StringsConvertor/input/it_IT/app.json | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/app.json b/Localization/StringsConvertor/input/it_IT/app.json index 841840ec..19c07e60 100644 --- a/Localization/StringsConvertor/input/it_IT/app.json +++ b/Localization/StringsConvertor/input/it_IT/app.json @@ -325,65 +325,65 @@ }, "dont_receive_email": { "title": "Controlla la tua e-mail", - "description": "Check if your email address is correct as well as your junk folder if you haven’t.", - "resend_email": "Resend Email" + "description": "Controlla se il tuo indirizzo email sia corretto, così come la tua cartella spazzatura se non ce l'hai.", + "resend_email": "Invia e-mail di nuovo" }, "open_email_app": { - "title": "Check your inbox.", - "description": "We just sent you an email. Check your junk folder if you haven’t.", - "mail": "Mail", - "open_email_client": "Open Email Client" + "title": "Controlla la tua posta in arrivo.", + "description": "Ti abbiamo appena inviato un'email. Controlla la tua cartella spazzatura se non ce l'hai.", + "mail": "Posta", + "open_email_client": "Apri client Email" } }, "home_timeline": { - "title": "Home", + "title": "Inizio", "navigation_bar_state": { - "offline": "Offline", - "new_posts": "See new posts", - "published": "Published!", - "Publishing": "Publishing post..." + "offline": "Non in linea", + "new_posts": "Vedi nuovi post", + "published": "Pubblicato!", + "Publishing": "Pubblicazione post..." } }, "suggestion_account": { - "title": "Find People to Follow", - "follow_explain": "When you follow someone, you’ll see their posts in your home feed." + "title": "Trova alcune persone da seguire", + "follow_explain": "Quando segui qualcuno, vedrai i loro post nella tua home feed." }, "compose": { "title": { - "new_post": "New Post", - "new_reply": "New Reply" + "new_post": "Nuovo post", + "new_reply": "Nuova risposta" }, "media_selection": { - "camera": "Take Photo", - "photo_library": "Photo Library", - "browse": "Browse" + "camera": "Scatta foto", + "photo_library": "Libreria foto", + "browse": "Sfoglia" }, - "content_input_placeholder": "Type or paste what’s on your mind", - "compose_action": "Publish", - "replying_to_user": "replying to %s", + "content_input_placeholder": "Digita o incolla quello che hai in mente", + "compose_action": "Pubblica", + "replying_to_user": "rispondendo a %s", "attachment": { - "photo": "photo", - "video": "video", - "attachment_broken": "This %s is broken and can’t be\nuploaded to Mastodon.", - "description_photo": "Describe the photo for the visually-impaired...", - "description_video": "Describe the video for the visually-impaired..." + "photo": "foto", + "video": "filmato", + "attachment_broken": "Questo %s è rotto e non può essere\ncaricato su Mastodon.", + "description_photo": "Descrivi la foto per gli utenti ipovedenti...", + "description_video": "Descrivi il filmato per gli utenti ipovedenti..." }, "poll": { - "duration_time": "Duration: %s", - "thirty_minutes": "30 minutes", - "one_hour": "1 Hour", - "six_hours": "6 Hours", - "one_day": "1 Day", - "three_days": "3 Days", - "seven_days": "7 Days", - "option_number": "Option %ld" + "duration_time": "Durata: %s", + "thirty_minutes": "30 minuti", + "one_hour": "1 ora", + "six_hours": "6 ore", + "one_day": "1 giorno", + "three_days": "3 giorni", + "seven_days": "7 giorni", + "option_number": "Opzione %ld" }, "content_warning": { - "placeholder": "Write an accurate warning here..." + "placeholder": "Scrivi un avviso accurato qui..." }, "visibility": { - "public": "Public", - "unlisted": "Unlisted", + "public": "Pubblico", + "unlisted": "Non elencato", "private": "Followers only", "direct": "Only people I mention" }, From ee2de38ab67bff8f065cdc5148d1a06800b5cc3a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 14:54:38 +0200 Subject: [PATCH 089/188] New translations app.json (Vietnamese) --- .../StringsConvertor/input/vi_VN/app.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Localization/StringsConvertor/input/vi_VN/app.json b/Localization/StringsConvertor/input/vi_VN/app.json index e6e7a00e..4bb0f908 100644 --- a/Localization/StringsConvertor/input/vi_VN/app.json +++ b/Localization/StringsConvertor/input/vi_VN/app.json @@ -501,20 +501,20 @@ "Mentions": "Lượt nhắc đến" }, "notification_description": { - "followed_you": "followed you", - "favorited_your_post": "favorited your post", - "reblogged_your_post": "reblogged your post", - "mentioned_you": "mentioned you", - "request_to_follow_you": "request to follow you", - "poll_has_ended": "poll has ended" + "followed_you": "đã theo dõi bạn", + "favorited_your_post": "thích tút của bạn", + "reblogged_your_post": "đăng lại tút của bạn", + "mentioned_you": "nhắc đến bạn", + "request_to_follow_you": "yêu cầu theo dõi bạn", + "poll_has_ended": "cuộc bình chọn đã kết thúc" }, "keyobard": { - "show_everything": "Show Everything", - "show_mentions": "Show Mentions" + "show_everything": "Hiện mọi thứ", + "show_mentions": "Hiện lượt nhắc" } }, "thread": { - "back_title": "Post", + "back_title": "Tút", "title": "Post from %s" }, "settings": { From 3b9146b349282fca1f0dfc135708671c4bd68f66 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 16:07:02 +0200 Subject: [PATCH 090/188] New translations app.json (Italian) --- .../StringsConvertor/input/it_IT/app.json | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/app.json b/Localization/StringsConvertor/input/it_IT/app.json index 19c07e60..c839cbef 100644 --- a/Localization/StringsConvertor/input/it_IT/app.json +++ b/Localization/StringsConvertor/input/it_IT/app.json @@ -475,90 +475,90 @@ "accounts": { "title": "Accounts you might like", "description": "You may like to follow these accounts", - "follow": "Follow" + "follow": "Segui" } }, "searching": { "segment": { - "all": "All", - "people": "People", + "all": "Tutto", + "people": "Persone", "hashtags": "Hashtags", - "posts": "Posts" + "posts": "Post" }, "empty_state": { - "no_results": "No results" + "no_results": "Nessun risultato" }, - "recent_search": "Recent searches", - "clear": "Clear" + "recent_search": "Ricerche recenti", + "clear": "Cancella" } }, "favorite": { - "title": "Your Favorites" + "title": "I tuoi preferiti" }, "notification": { "title": { - "Everything": "Everything", - "Mentions": "Mentions" + "Everything": "Tutto", + "Mentions": "Menzioni" }, "notification_description": { - "followed_you": "followed you", - "favorited_your_post": "favorited your post", - "reblogged_your_post": "reblogged your post", - "mentioned_you": "mentioned you", - "request_to_follow_you": "request to follow you", - "poll_has_ended": "poll has ended" + "followed_you": "ti ha seguito", + "favorited_your_post": "ha apprezzato il tuo post", + "reblogged_your_post": "ha ripostato il tuo post", + "mentioned_you": "ti ha menzionato", + "request_to_follow_you": "richiesta di seguirti", + "poll_has_ended": "sondaggio terminato" }, "keyobard": { - "show_everything": "Show Everything", - "show_mentions": "Show Mentions" + "show_everything": "Mostra Tutto", + "show_mentions": "Mostra Menzioni" } }, "thread": { "back_title": "Post", - "title": "Post from %s" + "title": "Post da %s" }, "settings": { - "title": "Settings", + "title": "Impostazioni", "section": { "appearance": { - "title": "Appearance", - "automatic": "Automatic", - "light": "Always Light", - "dark": "Always Dark" + "title": "Aspetto", + "automatic": "Automatico", + "light": "Sempre chiaro", + "dark": "Sempre scuro" }, "look_and_feel": { "title": "Look and Feel", - "use_system": "Use System", - "really_dark": "Really Dark", - "sorta_dark": "Sorta Dark", - "light": "Light" + "use_system": "Predefinito di sistema", + "really_dark": "Davvero scuro", + "sorta_dark": "Un po' scuro", + "light": "Chiaro" }, "notifications": { - "title": "Notifications", - "favorites": "Favorites my post", - "follows": "Follows me", - "boosts": "Reblogs my post", - "mentions": "Mentions me", + "title": "Notifiche", + "favorites": "Apprezza i miei post", + "follows": "Mi segue", + "boosts": "Condivide i miei post", + "mentions": "Mi menziona", "trigger": { - "anyone": "anyone", - "follower": "a follower", - "follow": "anyone I follow", - "noone": "no one", - "title": "Notify me when" + "anyone": "chiunque", + "follower": "un seguace", + "follow": "chiunque io segua", + "noone": "nessuno", + "title": "Avvisami quando" } }, "preference": { - "title": "Preferences", - "true_black_dark_mode": "True black dark mode", - "disable_avatar_animation": "Disable animated avatars", - "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links", - "open_links_in_mastodon": "Open links in Mastodon" + "title": "Preferenze", + "true_black_dark_mode": "Modalità molto scura", + "disable_avatar_animation": "Disabilita avatar animati", + "disable_emoji_animation": "Disabilita emoji animate", + "using_default_browser": "Usa browser predefinito per aprire i collegamenti", + "open_links_in_mastodon": "Apri i link in Mastodon" }, "boring_zone": { - "title": "The Boring Zone", - "account_settings": "Account Settings", - "terms": "Terms of Service", + "title": "La zona boring", + "account_settings": "Impostazioni account", + "terms": "Termini di servizio", "privacy": "Privacy Policy" }, "spicy_zone": { From ce2aabb7cfea7d0d96d268b6063ec98e66240875 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 16:07:03 +0200 Subject: [PATCH 091/188] New translations app.json (Vietnamese) --- .../StringsConvertor/input/vi_VN/app.json | 112 +++++++++--------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/Localization/StringsConvertor/input/vi_VN/app.json b/Localization/StringsConvertor/input/vi_VN/app.json index 4bb0f908..eafd513b 100644 --- a/Localization/StringsConvertor/input/vi_VN/app.json +++ b/Localization/StringsConvertor/input/vi_VN/app.json @@ -515,94 +515,94 @@ }, "thread": { "back_title": "Tút", - "title": "Post from %s" + "title": "Tút của %s" }, "settings": { - "title": "Settings", + "title": "Cài đặt", "section": { "appearance": { - "title": "Appearance", - "automatic": "Automatic", - "light": "Always Light", - "dark": "Always Dark" + "title": "Giao diện", + "automatic": "Tự động", + "light": "Sáng", + "dark": "Tối" }, "look_and_feel": { - "title": "Look and Feel", - "use_system": "Use System", - "really_dark": "Really Dark", - "sorta_dark": "Sorta Dark", - "light": "Light" + "title": "Giao diện", + "use_system": "Mặc định hệ thống", + "really_dark": "Tối Mạnh", + "sorta_dark": "Tối Nhẹ", + "light": "Sáng" }, "notifications": { - "title": "Notifications", - "favorites": "Favorites my post", - "follows": "Follows me", - "boosts": "Reblogs my post", - "mentions": "Mentions me", + "title": "Thông báo", + "favorites": "Thích tút của tôi", + "follows": "Theo dõi tôi", + "boosts": "Đăng lại tút của tôi", + "mentions": "Nhắc đến tôi", "trigger": { - "anyone": "anyone", - "follower": "a follower", - "follow": "anyone I follow", - "noone": "no one", - "title": "Notify me when" + "anyone": "ai đó", + "follower": "người theo dõi", + "follow": "người tôi theo dõi", + "noone": "không một ai", + "title": "Thông báo khi" } }, "preference": { - "title": "Preferences", - "true_black_dark_mode": "True black dark mode", - "disable_avatar_animation": "Disable animated avatars", - "disable_emoji_animation": "Disable animated emojis", - "using_default_browser": "Use default browser to open links", - "open_links_in_mastodon": "Open links in Mastodon" + "title": "Chung", + "true_black_dark_mode": "Chế độ tối chân thật", + "disable_avatar_animation": "Tắt ảnh đại diện GIF", + "disable_emoji_animation": "Tắt emoji dạng GIF", + "using_default_browser": "Dùng trình duyệt mặc định", + "open_links_in_mastodon": "Mở liên kết trong Mastodon" }, "boring_zone": { - "title": "The Boring Zone", - "account_settings": "Account Settings", - "terms": "Terms of Service", - "privacy": "Privacy Policy" + "title": "Nhàm chán", + "account_settings": "Cài đặt tài khoản", + "terms": "Điều khoản dịch vụ", + "privacy": "Chính sách bảo mật" }, "spicy_zone": { - "title": "The Spicy Zone", - "clear": "Clear Media Cache", - "signout": "Sign Out" + "title": "Thú vị", + "clear": "Xóa bộ nhớ đệm", + "signout": "Đăng xuất" } }, "footer": { - "mastodon_description": "Mastodon is open source software. You can report issues on GitHub at %s (%s)" + "mastodon_description": "Mastodon là phần mềm mã nguồn mở. Bạn có thể báo lỗi trên GitHub tại %s (%s)" }, "keyboard": { - "close_settings_window": "Close Settings Window" + "close_settings_window": "Đóng cửa sổ cài đặt" } }, "report": { - "title_report": "Report", - "title": "Report %s", - "step1": "Step 1 of 2", - "step2": "Step 2 of 2", - "content1": "Are there any other posts you’d like to add to the report?", - "content2": "Is there anything the moderators should know about this report?", - "report_sent_title": "Thanks for reporting, we’ll look into this.", - "send": "Send Report", - "skip_to_send": "Send without comment", - "text_placeholder": "Type or paste additional comments", - "reported": "REPORTED" + "title_report": "Báo cáo", + "title": "Báo cáo %s", + "step1": "Bước 1 trong 2", + "step2": "Bước 2 trong 2", + "content1": "Bạn muốn thêm tút nào vào báo cáo nữa không?", + "content2": "Kiểm duyệt viên cần biết gì về báo cáo này?", + "report_sent_title": "Cảm ơn đã báo cáo, chúng tôi sẽ xem xét kỹ.", + "send": "Gửi báo cáo", + "skip_to_send": "Gửi không ghi chú", + "text_placeholder": "Nhập hoặc bổ sung chú thích", + "reported": "ĐÃ BÁO CÁO" }, "preview": { "keyboard": { - "close_preview": "Close Preview", - "show_next": "Show Next", - "show_previous": "Show Previous" + "close_preview": "Đóng xem trước", + "show_next": "Hiện kế tiếp", + "show_previous": "Hiện trước đó" } }, "account_list": { - "tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher", - "dismiss_account_switcher": "Dismiss Account Switcher", - "add_account": "Add Account" + "tab_bar_hint": "Đang dùng tài khoản: %s. Nhấn hai lần và giữ để đổi sang tài khoản khác", + "dismiss_account_switcher": "Bỏ qua chuyển đổi tài khoản", + "add_account": "Thêm tài khoản" }, "wizard": { - "new_in_mastodon": "New in Mastodon", - "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", - "accessibility_hint": "Double tap to dismiss this wizard" + "new_in_mastodon": "Mới trên Mastodon", + "multiple_account_switch_intro_description": "Chuyển đổi giữa nhiều tài khoản bằng cách đè giữ nút tài khoản.", + "accessibility_hint": "Nhấn hai lần để bỏ qua" } } } \ No newline at end of file From 1ae07f9c2f5b21062e617ddf34373c261d998fe6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 16:07:04 +0200 Subject: [PATCH 092/188] New translations ios-infoPlist.json (Vietnamese) --- .../StringsConvertor/input/vi_VN/ios-infoPlist.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/vi_VN/ios-infoPlist.json b/Localization/StringsConvertor/input/vi_VN/ios-infoPlist.json index c6db73de..2170219a 100644 --- a/Localization/StringsConvertor/input/vi_VN/ios-infoPlist.json +++ b/Localization/StringsConvertor/input/vi_VN/ios-infoPlist.json @@ -1,6 +1,6 @@ { - "NSCameraUsageDescription": "Used to take photo for post status", - "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library", - "NewPostShortcutItemTitle": "New Post", - "SearchShortcutItemTitle": "Search" + "NSCameraUsageDescription": "Được sử dụng để chụp ảnh cho tút", + "NSPhotoLibraryAddUsageDescription": "Được sử dụng để lưu ảnh vào Thư viện ảnh", + "NewPostShortcutItemTitle": "Viết tút", + "SearchShortcutItemTitle": "Tìm kiếm" } From 8a7fc8e6ee213f8975e21cbdf612aa8de64798c5 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 16:07:05 +0200 Subject: [PATCH 093/188] New translations Localizable.stringsdict (Vietnamese) --- .../input/vi_VN/Localizable.stringsdict | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/Localization/StringsConvertor/input/vi_VN/Localizable.stringsdict b/Localization/StringsConvertor/input/vi_VN/Localizable.stringsdict index c69fd562..71ba1951 100644 --- a/Localization/StringsConvertor/input/vi_VN/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/vi_VN/Localizable.stringsdict @@ -13,13 +13,13 @@ NSStringFormatValueTypeKey ld other - %ld unread notification + %ld thông báo chưa đọc a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + Giới hạn nhập tối đa %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -27,13 +27,13 @@ NSStringFormatValueTypeKey ld other - %ld characters + %ld ký tự a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + Giới hạn nhập còn lại %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -41,7 +41,7 @@ NSStringFormatValueTypeKey ld other - %ld characters + %ld ký tự plural.count.metric_formatted.post @@ -55,7 +55,7 @@ NSStringFormatValueTypeKey ld other - posts + tút plural.count.post @@ -69,7 +69,7 @@ NSStringFormatValueTypeKey ld other - %ld posts + %ld tút plural.count.favorite @@ -83,7 +83,7 @@ NSStringFormatValueTypeKey ld other - %ld favorites + %ld lượt thích plural.count.reblog @@ -97,7 +97,7 @@ NSStringFormatValueTypeKey ld other - %ld reblogs + %ld đăng lại plural.count.reply @@ -111,7 +111,7 @@ NSStringFormatValueTypeKey ld other - %ld replies + %ld trả lời plural.count.vote @@ -125,7 +125,7 @@ NSStringFormatValueTypeKey ld other - %ld votes + %ld bình chọn plural.count.voter @@ -139,7 +139,7 @@ NSStringFormatValueTypeKey ld other - %ld voters + %ld người bình chọn plural.people_talking @@ -153,7 +153,7 @@ NSStringFormatValueTypeKey ld other - %ld people talking + %ld người đang thảo luận plural.count.following @@ -167,7 +167,7 @@ NSStringFormatValueTypeKey ld other - %ld following + %ld đang theo dõi plural.count.follower @@ -181,7 +181,7 @@ NSStringFormatValueTypeKey ld other - %ld followers + %ld người theo dõi date.year.left @@ -195,7 +195,7 @@ NSStringFormatValueTypeKey ld other - %ld years left + %ld năm còn lại date.month.left @@ -209,7 +209,7 @@ NSStringFormatValueTypeKey ld other - %ld months left + %ld tháng còn lại date.day.left @@ -223,7 +223,7 @@ NSStringFormatValueTypeKey ld other - %ld days left + %ld ngày còn lại date.hour.left @@ -237,7 +237,7 @@ NSStringFormatValueTypeKey ld other - %ld hours left + %ld giờ còn lại date.minute.left @@ -251,7 +251,7 @@ NSStringFormatValueTypeKey ld other - %ld minutes left + %ld phút còn lại date.second.left @@ -265,7 +265,7 @@ NSStringFormatValueTypeKey ld other - %ld seconds left + %ld giây còn lại date.year.ago.abbr @@ -279,7 +279,7 @@ NSStringFormatValueTypeKey ld other - %ldy ago + %ld năm trước date.month.ago.abbr @@ -293,7 +293,7 @@ NSStringFormatValueTypeKey ld other - %ldM ago + %ld tháng trước date.day.ago.abbr @@ -307,7 +307,7 @@ NSStringFormatValueTypeKey ld other - %ldd ago + %ld ngày trước date.hour.ago.abbr @@ -321,7 +321,7 @@ NSStringFormatValueTypeKey ld other - %ldh ago + %ldh date.minute.ago.abbr @@ -335,7 +335,7 @@ NSStringFormatValueTypeKey ld other - %ldm ago + %ldm date.second.ago.abbr @@ -349,7 +349,7 @@ NSStringFormatValueTypeKey ld other - %lds ago + %lds From 4c61e9ab140138ff92e003dbb226d0681946ce6c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 16:07:09 +0200 Subject: [PATCH 094/188] New translations Intents.strings (Vietnamese) --- .../Intents/input/vi_VN/Intents.strings | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/vi_VN/Intents.strings b/Localization/StringsConvertor/Intents/input/vi_VN/Intents.strings index 6877490b..a9533731 100644 --- a/Localization/StringsConvertor/Intents/input/vi_VN/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/vi_VN/Intents.strings @@ -1,51 +1,51 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "Đăng lên Mastodon"; -"751xkl" = "Text Content"; +"751xkl" = "Nội dung văn bản"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "Đăng lên Mastodon"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Đăng loại nội dung nào?"; -"HdGikU" = "Posting failed"; +"HdGikU" = "Không thể đăng"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "Lý do không thể đăng"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Gửi tút với nội dung là chữ"; -"RxSqsb" = "Post"; +"RxSqsb" = "Tút"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "Đăng ${content} lên Mastodon"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "Tút"; "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "Hiển thị"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "Thay đổi quyền riêng tư"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Có ${count} lựa chọn khớp với ‘Công khai’."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Có ${count} lựa chọn khớp với ‘Riêng tư’."; -"ayoYEb-dYQ5NN" = "${content}, Public"; +"ayoYEb-dYQ5NN" = "${content}, Công khai"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}, Riêng tư"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "Đăng lên Mastodon"; -"dYQ5NN" = "Public"; +"dYQ5NN" = "Công khai"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "Riêng tư"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "Không thể đăng. ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "Đã đăng tút thành công."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "Xin xác nhận, bạn muốn ‘Công khai’?"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "Xin xác nhận, bạn muốn ‘Riêng tư’?"; "rM6dvp" = "URL"; -"ryJLwG" = "Post was sent successfully. "; +"ryJLwG" = "Đã đăng tút thành công. "; From 481dcc7b4a3082ed0abe11c2e9e11a7537dbd1f8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 16:07:11 +0200 Subject: [PATCH 095/188] New translations Intents.stringsdict (Vietnamese) --- .../Intents/input/vi_VN/Intents.stringsdict | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/vi_VN/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/vi_VN/Intents.stringsdict index a14f8b9f..a4bb783d 100644 --- a/Localization/StringsConvertor/Intents/input/vi_VN/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/vi_VN/Intents.stringsdict @@ -5,7 +5,7 @@ There are ${count} options matching ‘${content}’. - 2 NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${content}’. + Có %#@count_option@ khớp với ‘${content}’. count_option NSStringFormatSpecTypeKey @@ -13,13 +13,13 @@ NSStringFormatValueTypeKey %ld other - %ld options + %ld lựa chọn There are ${count} options matching ‘${visibility}’. NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${visibility}’. + Có %#@count_option@ khớp với ‘${visibility}’. count_option NSStringFormatSpecTypeKey @@ -27,7 +27,7 @@ NSStringFormatValueTypeKey %ld other - %ld options + %ld lựa chọn From 38d8200ba94025294eb296a658479c60db540dc8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 20:57:50 +0200 Subject: [PATCH 096/188] New translations Localizable.stringsdict (Italian) --- .../input/it_IT/Localizable.stringsdict | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict b/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict index 503ff9db..48222f42 100644 --- a/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict @@ -13,15 +13,15 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 notifica non letta other - %ld unread notification + %ld notifiche non lette a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + Il limite di input supera %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -29,15 +29,15 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 carattere other - %ld characters + %ld caratteri a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + Il limite di input rimane %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -45,9 +45,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 carattere other - %ld characters + %ld caratteri plural.count.metric_formatted.post @@ -63,7 +63,7 @@ one post other - posts + post plural.count.post @@ -79,7 +79,7 @@ one 1 post other - %ld posts + %ld post plural.count.favorite @@ -93,7 +93,7 @@ NSStringFormatValueTypeKey ld one - 1 favorite + 1 preferito other %ld favorites @@ -109,9 +109,9 @@ NSStringFormatValueTypeKey ld one - 1 reblog + 1 condivisione other - %ld reblogs + %ld condivisioni plural.count.reply @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 risposta other - %ld replies + %ld risposte plural.count.vote @@ -141,9 +141,9 @@ NSStringFormatValueTypeKey ld one - 1 vote + 1 voto other - %ld votes + %ld voti plural.count.voter @@ -157,9 +157,9 @@ NSStringFormatValueTypeKey ld one - 1 voter + 1 votante other - %ld voters + %ld votanti plural.people_talking @@ -173,9 +173,9 @@ NSStringFormatValueTypeKey ld one - 1 people talking + 1 persona ne parla other - %ld people talking + %ld persone ne parlano plural.count.following @@ -189,7 +189,7 @@ NSStringFormatValueTypeKey ld one - 1 following + 1 seguace other %ld following From 009f40351677c565109b26220e95cad24c1ff74f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 31 Mar 2022 20:57:51 +0200 Subject: [PATCH 097/188] New translations ios-infoPlist.json (Italian) --- .../StringsConvertor/input/it_IT/ios-infoPlist.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/ios-infoPlist.json b/Localization/StringsConvertor/input/it_IT/ios-infoPlist.json index c6db73de..bca6817f 100644 --- a/Localization/StringsConvertor/input/it_IT/ios-infoPlist.json +++ b/Localization/StringsConvertor/input/it_IT/ios-infoPlist.json @@ -1,6 +1,6 @@ { - "NSCameraUsageDescription": "Used to take photo for post status", - "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library", - "NewPostShortcutItemTitle": "New Post", - "SearchShortcutItemTitle": "Search" + "NSCameraUsageDescription": "Usato per scattare foto per lo stato del post", + "NSPhotoLibraryAddUsageDescription": "Utilizzato per salvare la foto nella galleria immagini", + "NewPostShortcutItemTitle": "Nuovo post", + "SearchShortcutItemTitle": "Cerca" } From 80702e81af0885ae5d9880ad56a76fab86a2dc27 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 1 Apr 2022 09:48:48 +0800 Subject: [PATCH 098/188] feat: add language Kabyle and Vietnamese --- .../Sources/StringsConvertor/main.swift | 2 + Mastodon.xcodeproj/project.pbxproj | 14 +++++ .../xcschemes/xcschememanagement.plist | 6 +-- .../Resources/kab.lproj/InfoPlist.strings | 4 ++ Mastodon/Resources/vi.lproj/InfoPlist.strings | 4 ++ MastodonIntent/kab.lproj/Intents.strings | 52 ++++++++++++++++++ MastodonIntent/kab.lproj/Intents.stringsdict | 54 +++++++++++++++++++ MastodonIntent/vi.lproj/Intents.strings | 52 ++++++++++++++++++ MastodonIntent/vi.lproj/Intents.stringsdict | 54 +++++++++++++++++++ 9 files changed, 239 insertions(+), 3 deletions(-) create mode 100644 Mastodon/Resources/kab.lproj/InfoPlist.strings create mode 100644 Mastodon/Resources/vi.lproj/InfoPlist.strings create mode 100644 MastodonIntent/kab.lproj/Intents.strings create mode 100644 MastodonIntent/kab.lproj/Intents.stringsdict create mode 100644 MastodonIntent/vi.lproj/Intents.strings create mode 100644 MastodonIntent/vi.lproj/Intents.stringsdict diff --git a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift index 14266a45..606a9520 100644 --- a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift +++ b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift @@ -56,6 +56,7 @@ private func map(language: String) -> String? { case "fr_FR": return "fr" // French case "de_DE": return "de" // German case "ja_JP": return "ja" // Japanese + case "kab_KAB": return "kab" // Kabyle case "kmr_TR": return "ku" // Kurmanji (Kurdish) case "ru_RU": return "ru" // Russian case "gd_GB": return "gd-GB" // Scottish Gaelic @@ -63,6 +64,7 @@ private func map(language: String) -> String? { case "es_AR": return "es-419" // Spanish, Argentina case "sv_FI": return "sv_FI" // Swedish, Finland case "th_TH": return "th" // Thai + case "vi_VN": return "vi" // Vietnamese default: return nil } } diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 69596a20..cbcd948b 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -1317,6 +1317,12 @@ DBF3B7402733EB9400E21627 /* MastodonLocalCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLocalCode.swift; sourceTree = ""; }; DBF53F5F25C14E88008AAC7B /* Mastodon.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = Mastodon.xctestplan; path = Mastodon/Mastodon.xctestplan; sourceTree = ""; }; DBF53F6025C14E9D008AAC7B /* MastodonSDK.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = MastodonSDK.xctestplan; sourceTree = ""; }; + DBF81C7427F68F5A00004A56 /* kab */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = kab; path = kab.lproj/Intents.strings; sourceTree = ""; }; + DBF81C7527F68F5A00004A56 /* kab */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = kab; path = kab.lproj/InfoPlist.strings; sourceTree = ""; }; + DBF81C7627F68F5A00004A56 /* kab */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = kab; path = kab.lproj/Intents.stringsdict; sourceTree = ""; }; + DBF81C7727F6913300004A56 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Intents.strings; sourceTree = ""; }; + DBF81C7827F6913300004A56 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/InfoPlist.strings; sourceTree = ""; }; + DBF81C7927F6913300004A56 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = vi; path = vi.lproj/Intents.stringsdict; sourceTree = ""; }; DBF8AE13263293E400C9C23C /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; }; DBF8AE15263293E400C9C23C /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; DBF8AE17263293E400C9C23C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -3441,6 +3447,8 @@ "eu-ES", "sv-FI", ku, + kab, + vi, ); mainGroup = DB427DC925BAA00100D1B89D; packageReferences = ( @@ -4442,6 +4450,8 @@ DB126A4C278C063F005726EE /* eu-ES */, DB126A56278C088D005726EE /* sv-FI */, DBEB19E927E4F37B00B0E80E /* ku */, + DBF81C7427F68F5A00004A56 /* kab */, + DBF81C7727F6913300004A56 /* vi */, ); name = Intents.intentdefinition; sourceTree = ""; @@ -4465,6 +4475,8 @@ DB126A4F278C063F005726EE /* eu-ES */, DB126A59278C088D005726EE /* sv-FI */, DBEB19EA27E4F37B00B0E80E /* ku */, + DBF81C7527F68F5A00004A56 /* kab */, + DBF81C7827F6913300004A56 /* vi */, ); name = InfoPlist.strings; sourceTree = ""; @@ -4504,6 +4516,8 @@ DB126A50278C063F005726EE /* eu-ES */, DB126A5A278C088D005726EE /* sv-FI */, DBEB19EB27E4F37B00B0E80E /* ku */, + DBF81C7627F68F5A00004A56 /* kab */, + DBF81C7927F6913300004A56 /* vi */, ); name = Intents.stringsdict; sourceTree = ""; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index a90323e9..be42f063 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -104,7 +104,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 49 + 23 MastodonIntents.xcscheme_^#shared#^_ @@ -119,12 +119,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 51 + 21 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 50 + 22 SuppressBuildableAutocreation diff --git a/Mastodon/Resources/kab.lproj/InfoPlist.strings b/Mastodon/Resources/kab.lproj/InfoPlist.strings new file mode 100644 index 00000000..71086557 --- /dev/null +++ b/Mastodon/Resources/kab.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +"NSCameraUsageDescription" = "Used to take photo for post status"; +"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library"; +"NewPostShortcutItemTitle" = "New Post"; +"SearchShortcutItemTitle" = "Search"; \ No newline at end of file diff --git a/Mastodon/Resources/vi.lproj/InfoPlist.strings b/Mastodon/Resources/vi.lproj/InfoPlist.strings new file mode 100644 index 00000000..71086557 --- /dev/null +++ b/Mastodon/Resources/vi.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +"NSCameraUsageDescription" = "Used to take photo for post status"; +"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library"; +"NewPostShortcutItemTitle" = "New Post"; +"SearchShortcutItemTitle" = "Search"; \ No newline at end of file diff --git a/MastodonIntent/kab.lproj/Intents.strings b/MastodonIntent/kab.lproj/Intents.strings new file mode 100644 index 00000000..b85bec4c --- /dev/null +++ b/MastodonIntent/kab.lproj/Intents.strings @@ -0,0 +1,52 @@ +"16wxgf" = "Post on Mastodon"; + +"751xkl" = "Text Content"; + +"CsR7G2" = "Post on Mastodon"; + +"HZSGTr" = "What content to post?"; + +"HdGikU" = "Posting failed"; + +"KDNTJ4" = "Failure Reason"; + +"RHxKOw" = "Send Post with text content"; + +"RxSqsb" = "Post"; + +"WCIR3D" = "Post ${content} on Mastodon"; + +"ZKJSNu" = "Post"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "Visibility"; + +"Zo4jgJ" = "Post Visibility"; + +"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; + +"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; + +"ayoYEb-dYQ5NN" = "${content}, Public"; + +"ayoYEb-ehFLjY" = "${content}, Followers Only"; + +"dUyuGg" = "Post on Mastodon"; + +"dYQ5NN" = "Public"; + +"ehFLjY" = "Followers Only"; + +"gfePDu" = "Posting failed. ${failureReason}"; + +"k7dbKQ" = "Post was sent successfully."; + +"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; + +"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; + +"rM6dvp" = "URL"; + +"ryJLwG" = "Post was sent successfully."; + diff --git a/MastodonIntent/kab.lproj/Intents.stringsdict b/MastodonIntent/kab.lproj/Intents.stringsdict new file mode 100644 index 00000000..5a39d5e6 --- /dev/null +++ b/MastodonIntent/kab.lproj/Intents.stringsdict @@ -0,0 +1,54 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${content}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${visibility}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + + diff --git a/MastodonIntent/vi.lproj/Intents.strings b/MastodonIntent/vi.lproj/Intents.strings new file mode 100644 index 00000000..b85bec4c --- /dev/null +++ b/MastodonIntent/vi.lproj/Intents.strings @@ -0,0 +1,52 @@ +"16wxgf" = "Post on Mastodon"; + +"751xkl" = "Text Content"; + +"CsR7G2" = "Post on Mastodon"; + +"HZSGTr" = "What content to post?"; + +"HdGikU" = "Posting failed"; + +"KDNTJ4" = "Failure Reason"; + +"RHxKOw" = "Send Post with text content"; + +"RxSqsb" = "Post"; + +"WCIR3D" = "Post ${content} on Mastodon"; + +"ZKJSNu" = "Post"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "Visibility"; + +"Zo4jgJ" = "Post Visibility"; + +"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; + +"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; + +"ayoYEb-dYQ5NN" = "${content}, Public"; + +"ayoYEb-ehFLjY" = "${content}, Followers Only"; + +"dUyuGg" = "Post on Mastodon"; + +"dYQ5NN" = "Public"; + +"ehFLjY" = "Followers Only"; + +"gfePDu" = "Posting failed. ${failureReason}"; + +"k7dbKQ" = "Post was sent successfully."; + +"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; + +"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; + +"rM6dvp" = "URL"; + +"ryJLwG" = "Post was sent successfully."; + diff --git a/MastodonIntent/vi.lproj/Intents.stringsdict b/MastodonIntent/vi.lproj/Intents.stringsdict new file mode 100644 index 00000000..5a39d5e6 --- /dev/null +++ b/MastodonIntent/vi.lproj/Intents.stringsdict @@ -0,0 +1,54 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${content}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${visibility}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + + From 8a8ac759e094b9284faf5b25a0bfed20374dd590 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 1 Apr 2022 10:04:38 +0800 Subject: [PATCH 099/188] chore: update i18n resources --- .../xcschemes/xcschememanagement.plist | 15 +- MastodonIntent/ar.lproj/Intents.strings | 8 +- MastodonIntent/kab.lproj/Intents.strings | 49 ++- MastodonIntent/vi.lproj/Intents.strings | 49 ++- .../Generated/Strings.swift | 26 ++ .../Resources/ar.lproj/Localizable.strings | 88 ++-- .../ar.lproj/Localizable.stringsdict | 24 ++ .../Resources/ca.lproj/Localizable.strings | 10 + .../ca.lproj/Localizable.stringsdict | 16 + .../Resources/de.lproj/Localizable.strings | 10 + .../de.lproj/Localizable.stringsdict | 16 + .../Resources/en.lproj/Localizable.strings | 10 + .../en.lproj/Localizable.stringsdict | 16 + .../es-419.lproj/Localizable.strings | 10 + .../es-419.lproj/Localizable.stringsdict | 16 + .../Resources/es.lproj/Localizable.strings | 10 + .../es.lproj/Localizable.stringsdict | 16 + .../Resources/eu-ES.lproj/Localizable.strings | 10 + .../eu-ES.lproj/Localizable.stringsdict | 16 + .../Resources/fr.lproj/Localizable.strings | 10 + .../fr.lproj/Localizable.stringsdict | 16 + .../Resources/gd-GB.lproj/Localizable.strings | 10 + .../gd-GB.lproj/Localizable.stringsdict | 20 + .../Resources/ja.lproj/Localizable.strings | 10 + .../ja.lproj/Localizable.stringsdict | 14 + .../Resources/kab.lproj/Localizable.strings | 385 +++++++++++++++++ .../kab.lproj/Localizable.stringsdict | 406 ++++++++++++++++++ .../Resources/ku.lproj/Localizable.strings | 10 + .../ku.lproj/Localizable.stringsdict | 16 + .../Resources/nl.lproj/Localizable.strings | 10 + .../nl.lproj/Localizable.stringsdict | 16 + .../Resources/ru.lproj/Localizable.strings | 10 + .../ru.lproj/Localizable.stringsdict | 20 + .../Resources/sv_FI.lproj/Localizable.strings | 10 + .../sv_FI.lproj/Localizable.stringsdict | 16 + .../Resources/th.lproj/Localizable.strings | 10 + .../th.lproj/Localizable.stringsdict | 14 + .../Resources/vi.lproj/Localizable.strings | 385 +++++++++++++++++ .../vi.lproj/Localizable.stringsdict | 356 +++++++++++++++ .../zh-Hans.lproj/Localizable.strings | 10 + .../zh-Hans.lproj/Localizable.stringsdict | 14 + 41 files changed, 2085 insertions(+), 98 deletions(-) create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.stringsdict create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.stringsdict diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index be42f063..ad09868c 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -9,7 +9,7 @@ isShown orderHint - 3 + 4 CoreDataStack.xcscheme_^#shared#^_ @@ -19,7 +19,7 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 18 + 19 Mastodon - Release.xcscheme_^#shared#^_ @@ -31,6 +31,11 @@ orderHint 2 + Mastodon - ar.xcscheme + + orderHint + 3 + Mastodon - ar.xcscheme_^#shared#^_ orderHint @@ -104,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 23 + 24 MastodonIntents.xcscheme_^#shared#^_ @@ -119,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 21 + 22 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 22 + 23 SuppressBuildableAutocreation diff --git a/MastodonIntent/ar.lproj/Intents.strings b/MastodonIntent/ar.lproj/Intents.strings index cde27dc9..49183a43 100644 --- a/MastodonIntent/ar.lproj/Intents.strings +++ b/MastodonIntent/ar.lproj/Intents.strings @@ -1,4 +1,4 @@ -"16wxgf" = "النَشر على ماستودون"; +"16wxgf" = "النَّشرُ عَلَى مَاستودُون"; "751xkl" = "محتوى نصي"; @@ -14,7 +14,7 @@ "RxSqsb" = "مَنشور"; -"WCIR3D" = "نَشر ${content} على ماستودون"; +"WCIR3D" = "نَشرُ ${content} عَلَى مَاستودُون"; "ZKJSNu" = "مَنشور"; @@ -32,9 +32,9 @@ "ayoYEb-ehFLjY" = "${content}، المُتابِعُون فقط"; -"dUyuGg" = "النشر على ماستدون"; +"dUyuGg" = "النَّشرُ عَلَى مَاستودُون"; -"dYQ5NN" = "للعامة"; +"dYQ5NN" = "لِلعَامَّة"; "ehFLjY" = "لمتابعيك فقط"; diff --git a/MastodonIntent/kab.lproj/Intents.strings b/MastodonIntent/kab.lproj/Intents.strings index b85bec4c..532c822f 100644 --- a/MastodonIntent/kab.lproj/Intents.strings +++ b/MastodonIntent/kab.lproj/Intents.strings @@ -1,52 +1,51 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "Asuffeɣ deg Matodon"; -"751xkl" = "Text Content"; +"751xkl" = "Agbur n uḍris"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "Asuffeɣ deg Matodon"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Anwa agbur ara d-yettwasuffɣen?"; -"HdGikU" = "Posting failed"; +"HdGikU" = "Yecceḍ usuffeɣ"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "Ssebba n tuccḍa"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Azen tasuffeɣt s ugbur n uḍris"; -"RxSqsb" = "Post"; +"RxSqsb" = "Tasuffeɣt"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "Suffeɣ ${content} deg Mastodon"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "Tasuffeɣt"; "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "Abani"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "Abani n tsuffeɣt"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Yella ${count} n textiṛiyin yemṣadan d 'Uzayaz'."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Yella ${count} n textiṛiyin yemṣadan d 'Yineḍfaren kan'."; -"ayoYEb-dYQ5NN" = "${content}, Public"; +"ayoYEb-dYQ5NN" = "${content}, azayaz"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}, ineḍfaren kan"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "Asuffeɣ deg Maṣṭudun"; -"dYQ5NN" = "Public"; +"dYQ5NN" = "Azayez"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "Imeḍfaṛen kan"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "Asuffeɣ yecceḍ. ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "Tasuffeɣt tettwazen akken iwata."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "I usentem kan, tebɣiḍ 'Azayaz'?"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "I usentem kan, tebɣiḍ 'Ineḍfaren kan'?"; "rM6dvp" = "URL"; -"ryJLwG" = "Post was sent successfully."; - +"ryJLwG" = "Tasuffeɣt tettwazen akken iwata. "; diff --git a/MastodonIntent/vi.lproj/Intents.strings b/MastodonIntent/vi.lproj/Intents.strings index b85bec4c..a9533731 100644 --- a/MastodonIntent/vi.lproj/Intents.strings +++ b/MastodonIntent/vi.lproj/Intents.strings @@ -1,52 +1,51 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "Đăng lên Mastodon"; -"751xkl" = "Text Content"; +"751xkl" = "Nội dung văn bản"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "Đăng lên Mastodon"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Đăng loại nội dung nào?"; -"HdGikU" = "Posting failed"; +"HdGikU" = "Không thể đăng"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "Lý do không thể đăng"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Gửi tút với nội dung là chữ"; -"RxSqsb" = "Post"; +"RxSqsb" = "Tút"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "Đăng ${content} lên Mastodon"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "Tút"; "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "Hiển thị"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "Thay đổi quyền riêng tư"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Có ${count} lựa chọn khớp với ‘Công khai’."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Có ${count} lựa chọn khớp với ‘Riêng tư’."; -"ayoYEb-dYQ5NN" = "${content}, Public"; +"ayoYEb-dYQ5NN" = "${content}, Công khai"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}, Riêng tư"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "Đăng lên Mastodon"; -"dYQ5NN" = "Public"; +"dYQ5NN" = "Công khai"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "Riêng tư"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "Không thể đăng. ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "Đã đăng tút thành công."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "Xin xác nhận, bạn muốn ‘Công khai’?"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "Xin xác nhận, bạn muốn ‘Riêng tư’?"; "rM6dvp" = "URL"; -"ryJLwG" = "Post was sent successfully."; - +"ryJLwG" = "Đã đăng tút thành công. "; diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index 69e15f2d..15d786ef 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -274,6 +274,8 @@ public enum L10n { public static let showPost = L10n.tr("Localizable", "Common.Controls.Status.ShowPost") /// Show user profile public static let showUserProfile = L10n.tr("Localizable", "Common.Controls.Status.ShowUserProfile") + /// Tap to reveal + public static let tapToReveal = L10n.tr("Localizable", "Common.Controls.Status.TapToReveal") /// %@ reblogged public static func userReblogged(_ p1: Any) -> String { return L10n.tr("Localizable", "Common.Controls.Status.UserReblogged", String(describing: p1)) @@ -293,6 +295,14 @@ public enum L10n { public static let reblog = L10n.tr("Localizable", "Common.Controls.Status.Actions.Reblog") /// Reply public static let reply = L10n.tr("Localizable", "Common.Controls.Status.Actions.Reply") + /// Show GIF + public static let showGif = L10n.tr("Localizable", "Common.Controls.Status.Actions.ShowGif") + /// Show image + public static let showImage = L10n.tr("Localizable", "Common.Controls.Status.Actions.ShowImage") + /// Show video player + public static let showVideoPlayer = L10n.tr("Localizable", "Common.Controls.Status.Actions.ShowVideoPlayer") + /// Tap then hold to show menu + public static let tapThenHoldToShowMenu = L10n.tr("Localizable", "Common.Controls.Status.Actions.TapThenHoldToShowMenu") /// Unfavorite public static let unfavorite = L10n.tr("Localizable", "Common.Controls.Status.Actions.Unfavorite") /// Undo reblog @@ -598,6 +608,16 @@ public enum L10n { } } public enum Profile { + public enum Accessibility { + /// Double tap to open the list + public static let doubleTapToOpenTheList = L10n.tr("Localizable", "Scene.Profile.Accessibility.DoubleTapToOpenTheList") + /// Edit avatar image + public static let editAvatarImage = L10n.tr("Localizable", "Scene.Profile.Accessibility.EditAvatarImage") + /// Show avatar image + public static let showAvatarImage = L10n.tr("Localizable", "Scene.Profile.Accessibility.ShowAvatarImage") + /// Show banner image + public static let showBannerImage = L10n.tr("Localizable", "Scene.Profile.Accessibility.ShowBannerImage") + } public enum Dashboard { /// followers public static let followers = L10n.tr("Localizable", "Scene.Profile.Dashboard.Followers") @@ -1014,6 +1034,8 @@ public enum L10n { public static let disableAvatarAnimation = L10n.tr("Localizable", "Scene.Settings.Section.Preference.DisableAvatarAnimation") /// Disable animated emojis public static let disableEmojiAnimation = L10n.tr("Localizable", "Scene.Settings.Section.Preference.DisableEmojiAnimation") + /// Open links in Mastodon + public static let openLinksInMastodon = L10n.tr("Localizable", "Scene.Settings.Section.Preference.OpenLinksInMastodon") /// Preferences public static let title = L10n.tr("Localizable", "Scene.Settings.Section.Preference.Title") /// True black dark mode @@ -1185,6 +1207,10 @@ public enum L10n { public static func reblog(_ p1: Int) -> String { return L10n.tr("Localizable", "plural.count.reblog", p1) } + /// Plural format key: "%#@reply_count@" + public static func reply(_ p1: Int) -> String { + return L10n.tr("Localizable", "plural.count.reply", p1) + } /// Plural format key: "%#@vote_count@" public static func vote(_ p1: Int) -> String { return L10n.tr("Localizable", "plural.count.vote", p1) diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings index 668c7788..f26554fe 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings @@ -1,7 +1,7 @@ "Common.Alerts.BlockDomain.BlockEntireDomain" = "حظر النِّطاق"; "Common.Alerts.BlockDomain.Title" = "هل أنتَ مُتأكِّدٌ حقًا مِن رغبتك في حظر %@ بالكامل؟ في معظم الحالات، يكون مِنَ الكافي والمُفَضَّل استهداف عدد محدود للحظر أو الكتم. لن ترى محتوى من هذا النطاق وسوف يُزال جميع متابعيك المتواجدين فيه."; -"Common.Alerts.CleanCache.Message" = "تمَّ مَحو %@ مِن ذاكرة التخزين المؤقت بنجاح."; -"Common.Alerts.CleanCache.Title" = "مَحو ذاكرة التخزين المؤقت"; +"Common.Alerts.CleanCache.Message" = "مُحِيَ ما مَساحَتُهُ %@ مِن ذاكِرَةِ التَّخزينِ المُؤقَّت بِنجاح."; +"Common.Alerts.CleanCache.Title" = "مَحوُ ذاكِرَةِ التَّخزينِ المُؤقَّت"; "Common.Alerts.Common.PleaseTryAgain" = "يُرجى المُحاولة مرة أُخرى."; "Common.Alerts.Common.PleaseTryAgainLater" = "يُرجى المُحاولة مرة أُخرى لاحقًا."; "Common.Alerts.DeletePost.Message" = "هَل أنتَ مُتأكِدٌ مِن رَغبتِكَ فِي حَذفِ هَذَا المَنشُور؟"; @@ -18,9 +18,9 @@ "Common.Alerts.SavePhotoFailure.Message" = "يُرجى إتاحة إذن الوصول إلى مكتبة الصور لحفظ الصورة."; "Common.Alerts.SavePhotoFailure.Title" = "إخفاق في حفظ الصورة"; "Common.Alerts.ServerError.Title" = "خطأ في الخادم"; -"Common.Alerts.SignOut.Confirm" = "تسجيل الخروج"; +"Common.Alerts.SignOut.Confirm" = "تَسجيلُ الخُروج"; "Common.Alerts.SignOut.Message" = "هل أنت متأكد من رغبتك في تسجيل الخُروج؟"; -"Common.Alerts.SignOut.Title" = "تسجيل الخروج"; +"Common.Alerts.SignOut.Title" = "تَسجيلُ الخُروج"; "Common.Alerts.SignUpFailure.Title" = "إخفاق في التسجيل"; "Common.Alerts.VoteFailure.PollEnded" = "انتهى استطلاع الرأي"; "Common.Alerts.VoteFailure.Title" = "إخفاق في التصويت"; @@ -35,7 +35,7 @@ "Common.Controls.Actions.Delete" = "حذف"; "Common.Controls.Actions.Discard" = "تجاهُل"; "Common.Controls.Actions.Done" = "تمّ"; -"Common.Controls.Actions.Edit" = "تحرير"; +"Common.Controls.Actions.Edit" = "تَحرير"; "Common.Controls.Actions.FindPeople" = "ابحث عن أشخاص لِمُتابعتهم"; "Common.Controls.Actions.ManuallySearch" = "البحث يدويًا بدلًا من ذلك"; "Common.Controls.Actions.Next" = "التالي"; @@ -47,14 +47,14 @@ "Common.Controls.Actions.Previous" = "السابق"; "Common.Controls.Actions.Remove" = "حذف"; "Common.Controls.Actions.Reply" = "الرَّد"; -"Common.Controls.Actions.ReportUser" = "الإبلاغ عن %@"; +"Common.Controls.Actions.ReportUser" = "الإبلاغُ عَن %@"; "Common.Controls.Actions.Save" = "حفظ"; "Common.Controls.Actions.SavePhoto" = "حفظ الصورة"; "Common.Controls.Actions.SeeMore" = "عرض المزيد"; "Common.Controls.Actions.Settings" = "الإعدادات"; "Common.Controls.Actions.Share" = "المُشارك"; "Common.Controls.Actions.SharePost" = "مشارك المنشور"; -"Common.Controls.Actions.ShareUser" = "مُشاركة %@"; +"Common.Controls.Actions.ShareUser" = "مُشارَكَةُ %@"; "Common.Controls.Actions.SignIn" = "تسجيل الدخول"; "Common.Controls.Actions.SignUp" = "إنشاء حِساب"; "Common.Controls.Actions.Skip" = "تخطي"; @@ -63,13 +63,13 @@ "Common.Controls.Actions.UnblockDomain" = "رفع الحظر عن %@"; "Common.Controls.Friendship.Block" = "حظر"; "Common.Controls.Friendship.BlockDomain" = "حظر %@"; -"Common.Controls.Friendship.BlockUser" = "حظر %@"; +"Common.Controls.Friendship.BlockUser" = "حَظرُ %@"; "Common.Controls.Friendship.Blocked" = "محظور"; -"Common.Controls.Friendship.EditInfo" = "تعديل المعلومات"; +"Common.Controls.Friendship.EditInfo" = "تَحريرُ المَعلُومات"; "Common.Controls.Friendship.Follow" = "مُتابَعَة"; "Common.Controls.Friendship.Following" = "مُتابَع"; "Common.Controls.Friendship.Mute" = "كَتم"; -"Common.Controls.Friendship.MuteUser" = "كَتم %@"; +"Common.Controls.Friendship.MuteUser" = "كَتمُ %@"; "Common.Controls.Friendship.Muted" = "مكتوم"; "Common.Controls.Friendship.Pending" = "قيد المُراجعة"; "Common.Controls.Friendship.Request" = "إرسال طَلَب"; @@ -79,7 +79,7 @@ "Common.Controls.Friendship.UnmuteUser" = "رفع الكتم عن %@"; "Common.Controls.Keyboard.Common.ComposeNewPost" = "تأليف منشور جديد"; "Common.Controls.Keyboard.Common.OpenSettings" = "فَتحُ الإعدادات"; -"Common.Controls.Keyboard.Common.ShowFavorites" = "إظهار المُفضَّلة"; +"Common.Controls.Keyboard.Common.ShowFavorites" = "أظْهِر المُفضَّلة"; "Common.Controls.Keyboard.Common.SwitchToTab" = "التبديل إلى %@"; "Common.Controls.Keyboard.SegmentedControl.NextSection" = "القسم التالي"; "Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "القسم السابق"; @@ -98,21 +98,26 @@ "Common.Controls.Status.Actions.Menu" = "القائمة"; "Common.Controls.Status.Actions.Reblog" = "إعادة النشر"; "Common.Controls.Status.Actions.Reply" = "الرَّد"; +"Common.Controls.Status.Actions.ShowGif" = "أظْهِر GIF"; +"Common.Controls.Status.Actions.ShowImage" = "أظْهِرِ الصُّورَة"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "أظْهِر مُشَغِّلَ المَقاطِعِ المَرئِيَّة"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "اُنقُر مُطَوَّلًا لِإظْهَارِ القائِمَة"; "Common.Controls.Status.Actions.Unfavorite" = "إزالة التفضيل"; "Common.Controls.Status.Actions.Unreblog" = "التراجُع عن إعادة النشر"; "Common.Controls.Status.ContentWarning" = "تحذير المُحتوى"; -"Common.Controls.Status.MediaContentWarning" = "انقر للكشف"; +"Common.Controls.Status.MediaContentWarning" = "اُنقُر لِلكَشف"; "Common.Controls.Status.Poll.Closed" = "انتهى"; "Common.Controls.Status.Poll.Vote" = "صَوِّت"; -"Common.Controls.Status.ShowPost" = "إظهار منشور"; -"Common.Controls.Status.ShowUserProfile" = "إظهار الملف التعريفي للمُستخدِم"; -"Common.Controls.Status.Tag.Email" = "بريد إلكتروني"; +"Common.Controls.Status.ShowPost" = "أظْهِر مَنشور"; +"Common.Controls.Status.ShowUserProfile" = "أظْهِر المِلَفَّ التَّعريفِيَّ لِلمُستَخدِم"; +"Common.Controls.Status.Tag.Email" = "بَريدٌ إلِكتُرُونِيّ"; "Common.Controls.Status.Tag.Emoji" = "رمز تعبيري"; "Common.Controls.Status.Tag.Hashtag" = "وسم"; "Common.Controls.Status.Tag.Link" = "رابط"; "Common.Controls.Status.Tag.Mention" = "إشارة"; "Common.Controls.Status.Tag.Url" = "عنوان URL"; -"Common.Controls.Status.UserReblogged" = "أعادَ %@ تدوينها"; +"Common.Controls.Status.TapToReveal" = "اُنقُر لِلكَشف"; +"Common.Controls.Status.UserReblogged" = "أعادَ %@ تَدوينَها"; "Common.Controls.Status.UserRepliedTo" = "رَدًا على %@"; "Common.Controls.Status.Visibility.Direct" = "المُستخدمِونَ المُشارِ إليهم فَقَطْ مَن يُمكِنُهُم رُؤيَةُ هَذَا المَنشُور."; "Common.Controls.Status.Visibility.Private" = "فَقَطْ مُتابِعينَهُم مَن يُمكِنُهُم رُؤيَةُ هَذَا المَنشُور."; @@ -138,11 +143,11 @@ "Common.Controls.Timeline.Header.UserSuspendedWarning" = "لقد أُوقِفَ حِساب %@."; "Common.Controls.Timeline.Loader.LoadMissingPosts" = "تحميل المَنشورات المَفقودَة"; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "يَجري تحميل المَنشورات المَفقودَة..."; -"Common.Controls.Timeline.Loader.ShowMoreReplies" = "إظهار مَزيد مِنَ الرُّدود"; +"Common.Controls.Timeline.Loader.ShowMoreReplies" = "أظْهِر مَزيدًا مِنَ الرُّدود"; "Common.Controls.Timeline.Timestamp.Now" = "الآن"; "Scene.AccountList.AddAccount" = "إضافَةُ حِساب"; "Scene.AccountList.DismissAccountSwitcher" = "تجاهُل مبدِّل الحِساب"; -"Scene.AccountList.TabBarHint" = "المِلف المُحدَّد حاليًا: %@. انقر نقرًا مزدوجًا مع الاستمرار لإظهار مُبدِّل الحِساب"; +"Scene.AccountList.TabBarHint" = "المِلَفُّ المُحدَّدُ حالِيًّا: %@. اُنقُر نَقرًا مُزدَوَجًا مَعَ الاِستِمرارِ لِإظهارِ مُبدِّلِ الحِساب"; "Scene.Compose.Accessibility.AppendAttachment" = "إضافة مُرفَق"; "Scene.Compose.Accessibility.AppendPoll" = "اضافة استطلاع رأي"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "منتقي الرموز التعبيرية المُخصَّص"; @@ -178,11 +183,11 @@ "Scene.Compose.Poll.ThirtyMinutes" = "ثلاثون دقيقة"; "Scene.Compose.Poll.ThreeDays" = "ثلاثةُ أيام"; "Scene.Compose.ReplyingToUser" = "رَدًا على %@"; -"Scene.Compose.Title.NewPost" = "منشور جديد"; +"Scene.Compose.Title.NewPost" = "مَنشُورٌ جَديد"; "Scene.Compose.Title.NewReply" = "رَدٌّ جديد"; -"Scene.Compose.Visibility.Direct" = "للأشخاص المُشار إليهم فقط"; +"Scene.Compose.Visibility.Direct" = "لِمَن أشرتُ إليهِم فَقَط"; "Scene.Compose.Visibility.Private" = "للمُتابِعينَ فقط"; -"Scene.Compose.Visibility.Public" = "للعامة"; +"Scene.Compose.Visibility.Public" = "لِلعَامَّة"; "Scene.Compose.Visibility.Unlisted" = "غير مُدرَج"; "Scene.ConfirmEmail.Button.OpenEmailApp" = "فتح تطبيق البريد الإلكتروني"; "Scene.ConfirmEmail.Button.Resend" = "إعادَةُ الإرسال"; @@ -204,8 +209,8 @@ "Scene.HomeTimeline.NavigationBarState.Published" = "تمَّ النَّشر!"; "Scene.HomeTimeline.NavigationBarState.Publishing" = "يَجري نَشر المُشارَكَة..."; "Scene.HomeTimeline.Title" = "الرَّئِيسَة"; -"Scene.Notification.Keyobard.ShowEverything" = "إظهار كل شيء"; -"Scene.Notification.Keyobard.ShowMentions" = "إظهار الإشارات"; +"Scene.Notification.Keyobard.ShowEverything" = "أظْهِر كُلَّ شَيء"; +"Scene.Notification.Keyobard.ShowMentions" = "أظْهِر الإشارَات"; "Scene.Notification.NotificationDescription.FavoritedYourPost" = "فَضَّلَ مَنشُورَك"; "Scene.Notification.NotificationDescription.FollowedYou" = "بَدَأ بِمُتابَعَتِك"; "Scene.Notification.NotificationDescription.MentionedYou" = "أشارَ إليك"; @@ -215,9 +220,13 @@ "Scene.Notification.Title.Everything" = "كُلُّ شيء"; "Scene.Notification.Title.Mentions" = "الإشارات"; "Scene.Preview.Keyboard.ClosePreview" = "إغلاق المُعايَنَة"; -"Scene.Preview.Keyboard.ShowNext" = "إظهار التالي"; -"Scene.Preview.Keyboard.ShowPrevious" = "إظهار السابق"; -"Scene.Profile.Dashboard.Followers" = "متابِع"; +"Scene.Preview.Keyboard.ShowNext" = "أظْهِر التَّالي"; +"Scene.Preview.Keyboard.ShowPrevious" = "أظْهِر السَّابِق"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "اُنقُر نَقرًا مُزدَوَجًا لِفَتحِ القائِمَة"; +"Scene.Profile.Accessibility.EditAvatarImage" = "تَحريرُ الصُّورَةِ الرَّمزِيَّة"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "أظْهِر الصُّورَةَ الرَّمزِيَّة"; +"Scene.Profile.Accessibility.ShowBannerImage" = "أظْهِر صُورَةَ الرَّايَة"; +"Scene.Profile.Dashboard.Followers" = "مُتابِع"; "Scene.Profile.Dashboard.Following" = "مُتابَع"; "Scene.Profile.Dashboard.Posts" = "مَنشورات"; "Scene.Profile.Fields.AddRow" = "إضافة صف"; @@ -234,14 +243,14 @@ "Scene.Profile.SegmentedControl.About" = "حَول"; "Scene.Profile.SegmentedControl.Media" = "وَسائِط"; "Scene.Profile.SegmentedControl.Posts" = "مَنشورات"; -"Scene.Profile.SegmentedControl.PostsAndReplies" = "المَنشوراتُ وَالرُدود"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "مَنشُوراتٌ وَرُدُود"; "Scene.Profile.SegmentedControl.Replies" = "رُدُود"; "Scene.Register.Error.Item.Agreement" = "الاِتِّفاقيَّة"; "Scene.Register.Error.Item.Email" = "البريد الإلكتروني"; "Scene.Register.Error.Item.Locale" = "اللغة المحلية"; "Scene.Register.Error.Item.Password" = "الرمز السري"; "Scene.Register.Error.Item.Reason" = "السبب"; -"Scene.Register.Error.Item.Username" = "اِسم المُستَخدِم"; +"Scene.Register.Error.Item.Username" = "اِسمُ المُستَخدِم"; "Scene.Register.Error.Reason.Accepted" = "يجب أن يُقبل %@"; "Scene.Register.Error.Reason.Blank" = "%@ مَطلوب"; "Scene.Register.Error.Reason.Blocked" = "يحتوي %@ على موفِّر خدمة بريد إلكتروني غير مسموح به"; @@ -257,17 +266,17 @@ "Scene.Register.Error.Special.UsernameInvalid" = "يُمكِن أن يحتوي اسم المستخدم على أحرف أبجدية، أرقام وشرطات سفلية فقط"; "Scene.Register.Error.Special.UsernameTooLong" = "اِسم المُستَخدِم طويل جداً (يَجِبُ ألّا يكون أطول من ثلاثين خانة)"; "Scene.Register.Input.Avatar.Delete" = "حذف"; -"Scene.Register.Input.DisplayName.Placeholder" = "اِسم العَرض"; -"Scene.Register.Input.Email.Placeholder" = "بريد إلكتروني"; +"Scene.Register.Input.DisplayName.Placeholder" = "اِسمُ عَرض"; +"Scene.Register.Input.Email.Placeholder" = "بَريدٌ إلِكتُرُونِيّ"; "Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "لماذا ترغب في الانضمام؟"; "Scene.Register.Input.Password.Accessibility.Checked" = "مُتَحَققٌ مِنه"; "Scene.Register.Input.Password.Accessibility.Unchecked" = "غيرُ مُتَحَققٍ مِنه"; "Scene.Register.Input.Password.CharacterLimit" = "ثمانيةُ خانات"; -"Scene.Register.Input.Password.Hint" = "يجب أن يكون رمزك السري مكوَّن من ثمان خانات على الأقل"; +"Scene.Register.Input.Password.Hint" = "يَجِبُ أن يَحتَوي رَمزُكَ السِرِّيَ علَى ثَمانِ خاناتٍ أقلًا"; "Scene.Register.Input.Password.Placeholder" = "رمز سري"; "Scene.Register.Input.Password.Require" = "رمز المرور الخاص بك يجب أن يحتوي على الأقل:"; "Scene.Register.Input.Username.DuplicatePrompt" = "اِسم المُستَخدِم هذا مأخوذٌ بالفعل."; -"Scene.Register.Input.Username.Placeholder" = "اِسم مُستَخدِم"; +"Scene.Register.Input.Username.Placeholder" = "اِسمُ مُستَخدِم"; "Scene.Register.Title" = "أخبرنا عن نفسك."; "Scene.Report.Content1" = "هل ترغب في إضافة أي منشورات أُخرى إلى البلاغ؟"; "Scene.Report.Content2" = "هل هناك أي شيء يجب أن يعرفه المُراقبين حول هذا البلاغ؟"; @@ -286,17 +295,17 @@ "Scene.Search.Recommend.ButtonText" = "إظهار الكُل"; "Scene.Search.Recommend.HashTag.Description" = "الوُسُومُ الَّتي تَحظى بقدرٍ كبيرٍ مِنَ الاِهتمام"; "Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ أشخاص يتحدَّثوا"; -"Scene.Search.Recommend.HashTag.Title" = "ذُو شعبيَّة على ماستودون"; +"Scene.Search.Recommend.HashTag.Title" = "ذُو شَعبِيَّةٍ عَلَى مَاستودُون"; "Scene.Search.SearchBar.Cancel" = "إلغاء"; -"Scene.Search.SearchBar.Placeholder" = "البحث عن وسوم أو مستخدمين"; +"Scene.Search.SearchBar.Placeholder" = "اِبحَث عَن وُسُومٍ أو مُستَخدِمين"; "Scene.Search.Searching.Clear" = "مَحو"; "Scene.Search.Searching.EmptyState.NoResults" = "لا تُوجَدُ نتائِج"; "Scene.Search.Searching.RecentSearch" = "عَمَليَّاُت البَحثِ الأخيرَة"; "Scene.Search.Searching.Segment.All" = "الكُل"; -"Scene.Search.Searching.Segment.Hashtags" = "الوُسُوم"; -"Scene.Search.Searching.Segment.People" = "الأشخاص"; -"Scene.Search.Searching.Segment.Posts" = "المَنشورات"; -"Scene.Search.Title" = "البحث"; +"Scene.Search.Searching.Segment.Hashtags" = "وُسُوم"; +"Scene.Search.Searching.Segment.People" = "أشخاص"; +"Scene.Search.Searching.Segment.Posts" = "مَنشُورات"; +"Scene.Search.Title" = "البَحث"; "Scene.ServerPicker.Button.Category.Academia" = "أكاديمي"; "Scene.ServerPicker.Button.Category.Activism" = "النشطاء"; "Scene.ServerPicker.Button.Category.All" = "الكل"; @@ -357,10 +366,11 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "أشعِرني عِندما يَقومُ"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "تَعطيلُ الصوَرِ الرمزيَّةِ المُتحرِّكَة"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "تَعطيلُ الرُموزِ التَّعبيريَّةِ المُتحرِّكَة"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "فَتحُ الرَّوابِطِ فِي مَاستودُون"; "Scene.Settings.Section.Preference.Title" = "التَّفضيلات"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "النَّمَطُ الأسوَدُ الداكِنُ الحَقيقي"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "اِستِخدامُ المُتصفِّحِ الاِفتراضي لِفتحِ الرَّوابِط"; -"Scene.Settings.Section.SpicyZone.Clear" = "مَحوُ ذاكِرَةُ التَّخزينِ المُؤقت لِلوسائِط"; +"Scene.Settings.Section.SpicyZone.Clear" = "مَحوُ ذاكِرَةِ التَّخزينِ المُؤقَّتِ لِلوسائِط"; "Scene.Settings.Section.SpicyZone.Signout" = "تَسجيلُ الخُروج"; "Scene.Settings.Section.SpicyZone.Title" = "المنطِقَةُ اللَّاذِعَة"; "Scene.Settings.Title" = "الإعدادات"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict index 0b28c577..32782f1c 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict @@ -170,6 +170,30 @@ %ld إعادة تدوين + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + zero + لا رَدّ + one + رَدٌّ واحِد + two + رَدَّانِ اِثنان + few + %ld رُدُود + many + %ld رَدًّا + other + %ld رَدّ + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings index 8213aa3d..0cb63f34 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings @@ -98,6 +98,10 @@ Comprova la teva connexió a Internet."; "Common.Controls.Status.Actions.Menu" = "Menú"; "Common.Controls.Status.Actions.Reblog" = "Impuls"; "Common.Controls.Status.Actions.Reply" = "Respon"; +"Common.Controls.Status.Actions.ShowGif" = "Mostra el GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Mostra la imatge"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Mostra el reproductor de vídeo"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Toca i manté per a veure el menú"; "Common.Controls.Status.Actions.Unfavorite" = "Desfer Favorit"; "Common.Controls.Status.Actions.Unreblog" = "Desfer l'impuls"; "Common.Controls.Status.ContentWarning" = "Advertència de Contingut"; @@ -112,6 +116,7 @@ Comprova la teva connexió a Internet."; "Common.Controls.Status.Tag.Link" = "Enllaç"; "Common.Controls.Status.Tag.Mention" = "Menciona"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Toca per a mostrar"; "Common.Controls.Status.UserReblogged" = "%@ ha impulsat"; "Common.Controls.Status.UserRepliedTo" = "Ha respòs a %@"; "Common.Controls.Status.Visibility.Direct" = "Només l'usuari mencionat pot veure aquesta publicació."; @@ -217,6 +222,10 @@ toca l'enllaç per a confirmar el teu compte."; "Scene.Preview.Keyboard.ClosePreview" = "Tanca la Vista Prèvia"; "Scene.Preview.Keyboard.ShowNext" = "Mostrar Següent"; "Scene.Preview.Keyboard.ShowPrevious" = "Mostrar Anterior"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Doble toc per a veure la llista"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edita l'imatge del avatar"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Mostra l'imatge del avatar"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Mostra l'imatge del bàner"; "Scene.Profile.Dashboard.Followers" = "seguidors"; "Scene.Profile.Dashboard.Following" = "seguint"; "Scene.Profile.Dashboard.Posts" = "publicacions"; @@ -357,6 +366,7 @@ qualsevol servidor."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Notifica'm quan"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Desactiva avatars animats"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Desactiva emojis animats"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Obre enllaços a Mastodon"; "Scene.Settings.Section.Preference.Title" = "Preferències"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Mode negre fosc autèntic"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Utilitza el navegador predeterminat per a obrir enllaços"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.stringsdict index 140185ba..dfbd38c0 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld impulsos + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 Resposta + other + %ld respostes + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings index 8808e8d9..325b1e94 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings @@ -98,6 +98,10 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Status.Actions.Menu" = "Menü"; "Common.Controls.Status.Actions.Reblog" = "Teilen"; "Common.Controls.Status.Actions.Reply" = "Antworten"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "Aus Favoriten entfernen"; "Common.Controls.Status.Actions.Unreblog" = "Nicht mehr teilen"; "Common.Controls.Status.ContentWarning" = "Inhaltswarnung"; @@ -112,6 +116,7 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Status.Tag.Link" = "Link"; "Common.Controls.Status.Tag.Mention" = "Erwähnung"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@ teilte"; "Common.Controls.Status.UserRepliedTo" = "Antwortet auf %@"; "Common.Controls.Status.Visibility.Direct" = "Nur erwähnte Benutzer können diesen Beitrag sehen."; @@ -217,6 +222,10 @@ tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.Preview.Keyboard.ClosePreview" = "Vorschau schließen"; "Scene.Preview.Keyboard.ShowNext" = "Nächstes anzeigen"; "Scene.Preview.Keyboard.ShowPrevious" = "Vorheriges anzeigen"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; "Scene.Profile.Dashboard.Followers" = "Folger"; "Scene.Profile.Dashboard.Following" = "Gefolgte"; "Scene.Profile.Dashboard.Posts" = "Beiträge"; @@ -357,6 +366,7 @@ beliebigen Server."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Benachrichtige mich, wenn"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Animierte Profilbilder deaktivieren"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Animierte Emojis deaktivieren"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; "Scene.Settings.Section.Preference.Title" = "Präferenzen"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Vollständig dunkler Dunkelmodus"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Standardbrowser zum Öffnen von Links verwenden"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict index 66b7f2a2..cd721862 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld Reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings index 1a03cd56..285c185b 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -98,6 +98,10 @@ Please check your internet connection."; "Common.Controls.Status.Actions.Menu" = "Menu"; "Common.Controls.Status.Actions.Reblog" = "Reblog"; "Common.Controls.Status.Actions.Reply" = "Reply"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "Unfavorite"; "Common.Controls.Status.Actions.Unreblog" = "Undo reblog"; "Common.Controls.Status.ContentWarning" = "Content Warning"; @@ -112,6 +116,7 @@ Please check your internet connection."; "Common.Controls.Status.Tag.Link" = "Link"; "Common.Controls.Status.Tag.Mention" = "Mention"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@ reblogged"; "Common.Controls.Status.UserRepliedTo" = "Replied to %@"; "Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; @@ -216,6 +221,10 @@ uploaded to Mastodon."; "Scene.Preview.Keyboard.ClosePreview" = "Close Preview"; "Scene.Preview.Keyboard.ShowNext" = "Show Next"; "Scene.Preview.Keyboard.ShowPrevious" = "Show Previous"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; "Scene.Profile.Dashboard.Followers" = "followers"; "Scene.Profile.Dashboard.Following" = "following"; "Scene.Profile.Dashboard.Posts" = "posts"; @@ -355,6 +364,7 @@ uploaded to Mastodon."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Notify me when"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Disable animated avatars"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Disable animated emojis"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; "Scene.Settings.Section.Preference.Title" = "Preferences"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "True black dark mode"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Use default browser to open links"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.stringsdict index 730e2902..503ff9db 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings index d149865a..f3670fb6 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings @@ -98,6 +98,10 @@ Por favor, revisá tu conexión a Internet."; "Common.Controls.Status.Actions.Menu" = "Menú"; "Common.Controls.Status.Actions.Reblog" = "Adherir"; "Common.Controls.Status.Actions.Reply" = "Responder"; +"Common.Controls.Status.Actions.ShowGif" = "Mostrar GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Mostrar imagen"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Mostrar reproductor de video"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tocá y mantené presionado para mostrar el menú"; "Common.Controls.Status.Actions.Unfavorite" = "Dejar de marcar como favorito"; "Common.Controls.Status.Actions.Unreblog" = "Deshacer adhesión"; "Common.Controls.Status.ContentWarning" = "Advertencia de contenido"; @@ -112,6 +116,7 @@ Por favor, revisá tu conexión a Internet."; "Common.Controls.Status.Tag.Link" = "Enlace"; "Common.Controls.Status.Tag.Mention" = "Mención"; "Common.Controls.Status.Tag.Url" = "Dirección web"; +"Common.Controls.Status.TapToReveal" = "Tocá para mostrar"; "Common.Controls.Status.UserReblogged" = "%@ adhirió"; "Common.Controls.Status.UserRepliedTo" = "Respondió a %@"; "Common.Controls.Status.Visibility.Direct" = "Sólo el usuario mencionado puede ver este mensaje."; @@ -217,6 +222,10 @@ pulsá en el enlace para confirmar tu cuenta."; "Scene.Preview.Keyboard.ClosePreview" = "Cerrar previsualización"; "Scene.Preview.Keyboard.ShowNext" = "Mostrar siguiente"; "Scene.Preview.Keyboard.ShowPrevious" = "Mostrar anterior"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Tocá dos veces para abrir la lista"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Editar imagen de avatar"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Mostrar imagen de avatar"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Mostrar imagen de banner"; "Scene.Profile.Dashboard.Followers" = "seguidores"; "Scene.Profile.Dashboard.Following" = "siguiendo"; "Scene.Profile.Dashboard.Posts" = "mensajes"; @@ -357,6 +366,7 @@ el que quieras."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Notificarme cuando"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Deshabilitar avatares animados"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Deshabilitar emojis animados"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Abrir enlaces en Mastodon"; "Scene.Settings.Section.Preference.Title" = "Configuración"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Modo negro oscuro real"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Usar navegador web predeterminado para abrir enlaces"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.stringsdict index f4f0097e..9d1fdadb 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld adhesiones + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 respuesta + other + %ld respuestas + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings index 09814c91..4cbebb3e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings @@ -98,6 +98,10 @@ Por favor, revise su conexión a internet."; "Common.Controls.Status.Actions.Menu" = "Menú"; "Common.Controls.Status.Actions.Reblog" = "Rebloguear"; "Common.Controls.Status.Actions.Reply" = "Responder"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "No favorito"; "Common.Controls.Status.Actions.Unreblog" = "Deshacer reblogueo"; "Common.Controls.Status.ContentWarning" = "Advertencia de Contenido"; @@ -112,6 +116,7 @@ Por favor, revise su conexión a internet."; "Common.Controls.Status.Tag.Link" = "Enlace"; "Common.Controls.Status.Tag.Mention" = "Mención"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@ lo reblogueó"; "Common.Controls.Status.UserRepliedTo" = "En respuesta a %@"; "Common.Controls.Status.Visibility.Direct" = "Sólo el usuario mencionado puede ver este mensaje."; @@ -217,6 +222,10 @@ pulsa en el enlace para confirmar tu cuenta."; "Scene.Preview.Keyboard.ClosePreview" = "Cerrar Previsualización"; "Scene.Preview.Keyboard.ShowNext" = "Mostrar Siguiente"; "Scene.Preview.Keyboard.ShowPrevious" = "Mostrar Anterior"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; "Scene.Profile.Dashboard.Followers" = "seguidores"; "Scene.Profile.Dashboard.Following" = "siguiendo"; "Scene.Profile.Dashboard.Posts" = "publicaciones"; @@ -357,6 +366,7 @@ cualquier servidor."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Recibir notificación cuando"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Deshabilitar avatares animados"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Deshabilitar emojis animados"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; "Scene.Settings.Section.Preference.Title" = "Preferencias"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Modo oscuro negro real"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Usar navegador predeterminado para abrir los enlaces"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict index 186218af..24e407d0 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogueos + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings index 7feec0a7..341f4862 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings @@ -98,6 +98,10 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Status.Actions.Menu" = "Menua"; "Common.Controls.Status.Actions.Reblog" = "Bultzada"; "Common.Controls.Status.Actions.Reply" = "Erantzun"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "Kendu gogokoa"; "Common.Controls.Status.Actions.Unreblog" = "Desegin bultzada"; "Common.Controls.Status.ContentWarning" = "Edukiaren abisua"; @@ -112,6 +116,7 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Status.Tag.Link" = "Esteka"; "Common.Controls.Status.Tag.Mention" = "Aipatu"; "Common.Controls.Status.Tag.Url" = "URLa"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@ erabiltzaileak bultzada eman dio"; "Common.Controls.Status.UserRepliedTo" = "%@(r)i erantzuten"; "Common.Controls.Status.Visibility.Direct" = "Aipatutako erabiltzaileek soilik ikus dezakete bidalketa hau."; @@ -217,6 +222,10 @@ sakatu kontua berresteko esteka."; "Scene.Preview.Keyboard.ClosePreview" = "Itxi aurrebista"; "Scene.Preview.Keyboard.ShowNext" = "Erakutsi hurrengoa"; "Scene.Preview.Keyboard.ShowPrevious" = "Erakutsi aurrekoa"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; "Scene.Profile.Dashboard.Followers" = "jarraitzaile"; "Scene.Profile.Dashboard.Following" = "jarraitzen"; "Scene.Profile.Dashboard.Posts" = "bidalketa"; @@ -357,6 +366,7 @@ edozein zerbitzari."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Noiz jakinarazi:"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Desgaitu abatar animatuak"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Desgaitu emoji animatuak"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; "Scene.Settings.Section.Preference.Title" = "Hobespenak"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Benetako modu beltz iluna"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Erabili nabigatzaile lehenetsia estekak irekitzeko"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict index 817e8372..2069e27a 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld bultzada + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings index ffcd2846..69aa3172 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings @@ -98,6 +98,10 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Status.Actions.Menu" = "Menu"; "Common.Controls.Status.Actions.Reblog" = "Rebloguer"; "Common.Controls.Status.Actions.Reply" = "Répondre"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "Retirer des favoris"; "Common.Controls.Status.Actions.Unreblog" = "Annuler le reblog"; "Common.Controls.Status.ContentWarning" = "Avertissement de contenu"; @@ -112,6 +116,7 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Status.Tag.Link" = "Lien"; "Common.Controls.Status.Tag.Mention" = "Mention"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@ a reblogué"; "Common.Controls.Status.UserRepliedTo" = "À répondu à %@"; "Common.Controls.Status.Visibility.Direct" = "Seul·e l’utilisateur·rice mentionnée peut voir ce message."; @@ -217,6 +222,10 @@ tapotez le lien pour confirmer votre compte."; "Scene.Preview.Keyboard.ClosePreview" = "Fermer l'aperçu"; "Scene.Preview.Keyboard.ShowNext" = "Afficher le suivant"; "Scene.Preview.Keyboard.ShowPrevious" = "Afficher le précédent"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; "Scene.Profile.Dashboard.Followers" = "abonnés"; "Scene.Profile.Dashboard.Following" = "abonnements"; "Scene.Profile.Dashboard.Posts" = "publications"; @@ -357,6 +366,7 @@ n'importe quel serveur."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Me notifier lorsque"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Désactiver les avatars animés"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Désactiver les émojis animées"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; "Scene.Settings.Section.Preference.Title" = "Préférences"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Vrai mode sombre"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Utiliser le navigateur par défaut pour ouvrir les liens"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict index 37f07e67..93ee696f 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld reblogs + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings index be6ea23a..9e4ab602 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings @@ -98,6 +98,10 @@ Thoir sùil air a’ cheangal agad ris an eadar-lìon."; "Common.Controls.Status.Actions.Menu" = "Clàr-taice"; "Common.Controls.Status.Actions.Reblog" = "Brosnaich"; "Common.Controls.Status.Actions.Reply" = "Freagair"; +"Common.Controls.Status.Actions.ShowGif" = "Seall an GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Seall an dealbh"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Seall cluicheadair video"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Thoir gnogag ’s cùm sìos a shealltainn a’ chlàir-thaice"; "Common.Controls.Status.Actions.Unfavorite" = "Thoir air falbh o na h-annsachdan"; "Common.Controls.Status.Actions.Unreblog" = "Na brosnaich tuilleadh"; "Common.Controls.Status.ContentWarning" = "Rabhadh susbainte"; @@ -112,6 +116,7 @@ Thoir sùil air a’ cheangal agad ris an eadar-lìon."; "Common.Controls.Status.Tag.Link" = "Ceangal"; "Common.Controls.Status.Tag.Mention" = "Iomradh"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Thoir gnogag gus a nochdadh"; "Common.Controls.Status.UserReblogged" = "Tha %@ ’ga bhrosnachadh"; "Common.Controls.Status.UserRepliedTo" = "Air %@ fhreagairt"; "Common.Controls.Status.Visibility.Direct" = "Chan fhaic ach an cleachdaiche air an dugadh iomradh am post seo."; @@ -217,6 +222,10 @@ thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.Preview.Keyboard.ClosePreview" = "Dùin an ro-shealladh"; "Scene.Preview.Keyboard.ShowNext" = "Air adhart"; "Scene.Preview.Keyboard.ShowPrevious" = "Air ais"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Thoir gnogag dhùbailte a dh’fhosgladh na liosta"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Deasaich dealbh an avatar"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Seall dealbh an avatar"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Seall dealbh brataich"; "Scene.Profile.Dashboard.Followers" = "luchd-leantainn"; "Scene.Profile.Dashboard.Following" = "a’ leantainn"; "Scene.Profile.Dashboard.Posts" = "postaichean"; @@ -356,6 +365,7 @@ thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.Settings.Section.Notifications.Trigger.Title" = " "; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Cuir beothachadh nan avataran à comas"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Cuir beothachadh nan Emojis à comas"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Fosgail ceanglaichean ann am Mastodon"; "Scene.Settings.Section.Preference.Title" = "Roghainnean"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Modh dubh dorcha"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Cleachd am brabhsair bunaiteach airson ceanglaichean fhosgladh"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.stringsdict index 7a54f553..b149323e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.stringsdict @@ -142,6 +142,26 @@ %ld brosnachadh + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld fhreagairt + two + %ld fhreagairt + few + %ld freagairtean + other + %ld freagairt + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings index cb037936..a8164db9 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings @@ -98,6 +98,10 @@ "Common.Controls.Status.Actions.Menu" = "メニュー"; "Common.Controls.Status.Actions.Reblog" = "ブースト"; "Common.Controls.Status.Actions.Reply" = "リプライ"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "お気に入り登録を取り消す"; "Common.Controls.Status.Actions.Unreblog" = "ブーストを戻す"; "Common.Controls.Status.ContentWarning" = "コンテンツ警告"; @@ -112,6 +116,7 @@ "Common.Controls.Status.Tag.Link" = "リンク"; "Common.Controls.Status.Tag.Mention" = "メンション"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@がブースト"; "Common.Controls.Status.UserRepliedTo" = "%@がリプライ"; "Common.Controls.Status.Visibility.Direct" = "この投稿はメンションされたユーザーに限り見ることができます。"; @@ -211,6 +216,10 @@ "Scene.Preview.Keyboard.ClosePreview" = "プレビューを閉じる"; "Scene.Preview.Keyboard.ShowNext" = "次を見る"; "Scene.Preview.Keyboard.ShowPrevious" = "前を見る"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; "Scene.Profile.Dashboard.Followers" = "フォロワー"; "Scene.Profile.Dashboard.Following" = "フォロー"; "Scene.Profile.Dashboard.Posts" = "投稿"; @@ -350,6 +359,7 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "通知を受け取る"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "アバターのアニメーションを無効化する"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "絵文字のアニメーションを無効化する"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; "Scene.Settings.Section.Preference.Title" = "環境設定"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "真っ黒なダークテーマを使用する"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "既定のブラウザでリンクを開く"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.stringsdict index f1c5e6e2..8dfc9507 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.stringsdict @@ -100,6 +100,20 @@ %ld ブースト + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings new file mode 100644 index 00000000..55b8a3a6 --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings @@ -0,0 +1,385 @@ +"Common.Alerts.BlockDomain.BlockEntireDomain" = "Sewḥel taɣult"; +"Common.Alerts.BlockDomain.Title" = "D tidet, d tidet tebɣiḍ ad tesweḥleḍ %@ akken ma yella? Deg tuget, kra n yisewḥal d ugdal ad yili d ayen iwulmen, yettwafernen. Ur tettwaliḍ ara agbur seg taɣult-nni neɣ kra seg yineḍfaren-ik i tt-yesseqdacen."; +"Common.Alerts.CleanCache.Message" = "Yettwasfeḍ %@ n tkatut tuffirt akken iwata."; +"Common.Alerts.CleanCache.Title" = "Sfeḍ tuffirt"; +"Common.Alerts.Common.PleaseTryAgain" = "Ttxil εreḍ tikelt-nniḍen."; +"Common.Alerts.Common.PleaseTryAgainLater" = "Ttxil εreḍ tikelt-nniḍen ticki."; +"Common.Alerts.DeletePost.Message" = "Tebɣiḍ s tidet ad tekkseḍ tasuffeɣt-agi?"; +"Common.Alerts.DeletePost.Title" = "Tebɣiḍ s tidet ad tekkseḍ tasuffeɣt-agi?"; +"Common.Alerts.DiscardPostContent.Message" = "Sentem i wakken ad yettusefsax ugbur n tsuffeɣt."; +"Common.Alerts.DiscardPostContent.Title" = "Kkes arewway"; +"Common.Alerts.EditProfileFailure.Message" = "Yegguma ad yettwaẓreg umaɣnu. Ɛreḍ tikkelt-nniḍen."; +"Common.Alerts.EditProfileFailure.Title" = "Ẓreg tuccḍa n umaɣnu"; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Ur tezmireḍ ara ad ugar n tvidyut."; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Ur tezmireḍ ara ad tsedduḍ tavidyut deg tsuffeɣt ideg llant yakan tugniwin."; +"Common.Alerts.PublishPostFailure.Message" = "Yecceḍ usuffeɣ n tsuffeɣt. +Ma ulac aɣilif, senqed tuqqna-inek internet."; +"Common.Alerts.PublishPostFailure.Title" = "Yecceḍ usuffeɣ"; +"Common.Alerts.SavePhotoFailure.Message" = "Ma ulac aɣilif, rmed tasiregt n unekcum ɣer temkarḍit n tewlafin i usekles n tewlaft."; +"Common.Alerts.SavePhotoFailure.Title" = "Tuccḍa deg usekles n tewlaft"; +"Common.Alerts.ServerError.Title" = "Tuccḍa n uqeddac"; +"Common.Alerts.SignOut.Confirm" = "Ffeɣ"; +"Common.Alerts.SignOut.Message" = "Tebɣiḍ ad teffɣeḍ?"; +"Common.Alerts.SignOut.Title" = "Ffeɣ"; +"Common.Alerts.SignUpFailure.Title" = "Tuccḍa deg unekcum"; +"Common.Alerts.VoteFailure.PollEnded" = "Tafrant tfuk"; +"Common.Alerts.VoteFailure.Title" = "Tuccḍa deg ufran"; +"Common.Controls.Actions.Add" = "Rnu"; +"Common.Controls.Actions.Back" = "Tuɣalin"; +"Common.Controls.Actions.BlockDomain" = "Sewḥel %@"; +"Common.Controls.Actions.Cancel" = "Sefsex"; +"Common.Controls.Actions.Compose" = "Sudes"; +"Common.Controls.Actions.Confirm" = "Sentem"; +"Common.Controls.Actions.Continue" = "Kemmel"; +"Common.Controls.Actions.CopyPhoto" = "Nɣel tawlaft"; +"Common.Controls.Actions.Delete" = "Kkes"; +"Common.Controls.Actions.Discard" = "Sefsex"; +"Common.Controls.Actions.Done" = "Immed"; +"Common.Controls.Actions.Edit" = "Ẓreg"; +"Common.Controls.Actions.FindPeople" = "Af imdanen ara tḍefreḍ"; +"Common.Controls.Actions.ManuallySearch" = "Anadi s ufus deg wadeg-is"; +"Common.Controls.Actions.Next" = "Uḍfir"; +"Common.Controls.Actions.Ok" = "IH"; +"Common.Controls.Actions.Open" = "Ldi"; +"Common.Controls.Actions.OpenInBrowser" = "Ldi deg yiminig"; +"Common.Controls.Actions.OpenInSafari" = "Ldi deg Safari"; +"Common.Controls.Actions.Preview" = "Taskant"; +"Common.Controls.Actions.Previous" = "Uzwir"; +"Common.Controls.Actions.Remove" = "Kkes"; +"Common.Controls.Actions.Reply" = "Err"; +"Common.Controls.Actions.ReportUser" = "Cetki ɣef %@"; +"Common.Controls.Actions.Save" = "Sekles"; +"Common.Controls.Actions.SavePhoto" = "Sekles tawlaft"; +"Common.Controls.Actions.SeeMore" = "Wali ugar"; +"Common.Controls.Actions.Settings" = "Iɣewwaṛen"; +"Common.Controls.Actions.Share" = "Bḍu"; +"Common.Controls.Actions.SharePost" = "Bḍu tasuffeɣt"; +"Common.Controls.Actions.ShareUser" = "Bḍu %@"; +"Common.Controls.Actions.SignIn" = "Qqen"; +"Common.Controls.Actions.SignUp" = "Jerred amiḍan"; +"Common.Controls.Actions.Skip" = "Zgel"; +"Common.Controls.Actions.TakePhoto" = "Ṭṭef tawlaft"; +"Common.Controls.Actions.TryAgain" = "Ɛreḍ tikkelt-nniḍen"; +"Common.Controls.Actions.UnblockDomain" = "Serreḥ i %@"; +"Common.Controls.Friendship.Block" = "Sewḥel"; +"Common.Controls.Friendship.BlockDomain" = "Sewḥel %@"; +"Common.Controls.Friendship.BlockUser" = "Sewḥel %@"; +"Common.Controls.Friendship.Blocked" = "Yettusewḥel"; +"Common.Controls.Friendship.EditInfo" = "Ẓreg talɣut"; +"Common.Controls.Friendship.Follow" = "Ḍfeṛ"; +"Common.Controls.Friendship.Following" = "Yettwaḍfar"; +"Common.Controls.Friendship.Mute" = "Sgugem"; +"Common.Controls.Friendship.MuteUser" = "Sgugem %@"; +"Common.Controls.Friendship.Muted" = "Yettwasgugem"; +"Common.Controls.Friendship.Pending" = "Yegguni"; +"Common.Controls.Friendship.Request" = "Tuttra"; +"Common.Controls.Friendship.Unblock" = "Serreḥ"; +"Common.Controls.Friendship.UnblockUser" = "Serreḥ i %@"; +"Common.Controls.Friendship.Unmute" = "Kkes asgugem"; +"Common.Controls.Friendship.UnmuteUser" = "Kkes asgugem ɣef %@"; +"Common.Controls.Keyboard.Common.ComposeNewPost" = "Aru tasuffeɣt tamaynut"; +"Common.Controls.Keyboard.Common.OpenSettings" = "Ldi iɣewwaren"; +"Common.Controls.Keyboard.Common.ShowFavorites" = "Sken-d ismenyifen"; +"Common.Controls.Keyboard.Common.SwitchToTab" = "Ddu ɣer %@"; +"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Tigezmi tuḍfirt"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Tafrant tuzwirt"; +"Common.Controls.Keyboard.Timeline.NextStatus" = "Amagrad uḍfir"; +"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Ldi amaɣnu n umeskar"; +"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Ldi amaɣnu n win i yulsen asuffeɣ"; +"Common.Controls.Keyboard.Timeline.OpenStatus" = "Ldi tasuffeɣt"; +"Common.Controls.Keyboard.Timeline.PreviewImage" = "Asenqed n tugna"; +"Common.Controls.Keyboard.Timeline.PreviousStatus" = "Amagrad uzwir"; +"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Err ɣef tsuffeɣt"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Beddel alɣu n ugbur"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Abeddel n usmenyaf i tsuffeɣt"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Abeddel n unallas n tsuffeɣt"; +"Common.Controls.Status.Actions.Favorite" = "Anurif"; +"Common.Controls.Status.Actions.Hide" = "Ffer"; +"Common.Controls.Status.Actions.Menu" = "Umuɣ"; +"Common.Controls.Status.Actions.Reblog" = "Aɛiwed n usuffeɣ"; +"Common.Controls.Status.Actions.Reply" = "Err"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.Unfavorite" = "Kkes seg yismenyifen"; +"Common.Controls.Status.Actions.Unreblog" = "Sefsex allus n usuffeɣ"; +"Common.Controls.Status.ContentWarning" = "Alɣu n ugbur"; +"Common.Controls.Status.MediaContentWarning" = "Sit anida tebɣiḍ i wakken ad twaliḍ"; +"Common.Controls.Status.Poll.Closed" = "Ifukk"; +"Common.Controls.Status.Poll.Vote" = "Dɣeṛ"; +"Common.Controls.Status.ShowPost" = "Sken-d tasuffeɣt"; +"Common.Controls.Status.ShowUserProfile" = "Ssken-d amaɣnu n useqdac"; +"Common.Controls.Status.Tag.Email" = "Imayl"; +"Common.Controls.Status.Tag.Emoji" = "Emuji"; +"Common.Controls.Status.Tag.Hashtag" = "Ahacṭag"; +"Common.Controls.Status.Tag.Link" = "Aseɣwen"; +"Common.Controls.Status.Tag.Mention" = "Tabdart"; +"Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.UserReblogged" = "Tettwasuffeɣ-d %@ i tikkelt-nniḍen"; +"Common.Controls.Status.UserRepliedTo" = "Yerra ɣef %@"; +"Common.Controls.Status.Visibility.Direct" = "D ineḍfaren-is kan i izemren ad walin tsuffeɣ-a."; +"Common.Controls.Status.Visibility.Private" = "D ineḍfaren-is kan i izemren ad walin tsuffeɣ-a."; +"Common.Controls.Status.Visibility.PrivateFromMe" = "D ineḍfaren-is kan i izemren ad walin tsuffeɣ-a."; +"Common.Controls.Status.Visibility.Unlisted" = "Yal wa yezmer ad iwali tsuffeɣt-a maca ur d-tettwaskaneḍ ara deg yizirig n wakud azayaz."; +"Common.Controls.Tabs.Home" = "Agejdan"; +"Common.Controls.Tabs.Notification" = "Tilɣa"; +"Common.Controls.Tabs.Profile" = "Amaɣnu"; +"Common.Controls.Tabs.Search" = "Nadi"; +"Common.Controls.Timeline.Filtered" = "Yettwasizdeg"; +"Common.Controls.Timeline.Header.BlockedWarning" = "Ur tezmireḍ ara ad twaliḍ amaɣnu n useqdac-a +Akka i as-d-yettban umaɣnu-inek."; +"Common.Controls.Timeline.Header.BlockingWarning" = "Ur tezmireḍ ara ad twaliḍ amaɣnu n useqdac-a +alamma tekkseḍ-as asewḥel. +Akka i as-d-yettban umaɣnu-inek."; +"Common.Controls.Timeline.Header.NoStatusFound" = "Ulac tasuffeɣt yettwafen"; +"Common.Controls.Timeline.Header.SuspendedWarning" = "Yettwaseḥbes useqdac-a."; +"Common.Controls.Timeline.Header.UserBlockedWarning" = "Ur tezmireḍ ara ad twaliḍ amaɣnu n %@ +Akka i as-d-yettban umaɣnu-inek."; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "Ur tezmireḍ ara ad twaliḍ amaɣnu n %@ +alamma tekkseḍ-as asewḥel. +Akka i as-d-yettban umaɣnu-inek."; +"Common.Controls.Timeline.Header.UserSuspendedWarning" = "Yettwaseḥbes umiḍan n %@."; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Sali tisuffaɣ i iruḥen"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Asali n tsuffaɣ i iruḥen..."; +"Common.Controls.Timeline.Loader.ShowMoreReplies" = "Ssken-d ugar n tririyin"; +"Common.Controls.Timeline.Timestamp.Now" = "Tura"; +"Scene.AccountList.AddAccount" = "Rnu amiḍan"; +"Scene.AccountList.DismissAccountSwitcher" = "Sefsex abeddel n umiḍan"; +"Scene.AccountList.TabBarHint" = "Amaɣnu amiran yettwafernen: %@. Sit berdayen syen teǧǧeḍ aḍad-ik·im i uskan abeddel n umiḍan"; +"Scene.Compose.Accessibility.AppendAttachment" = "Rnu taceqquft yeddan"; +"Scene.Compose.Accessibility.AppendPoll" = "Rnu asenqed"; +"Scene.Compose.Accessibility.CustomEmojiPicker" = "Amefran n yimujiten udmawanen"; +"Scene.Compose.Accessibility.DisableContentWarning" = "Sens alɣu n ugbur"; +"Scene.Compose.Accessibility.EnableContentWarning" = "Rmed alɣu n ugbur"; +"Scene.Compose.Accessibility.PostVisibilityMenu" = "Umuɣ n ubani n tsuffeɣt"; +"Scene.Compose.Accessibility.RemovePoll" = "Kkes asenqed"; +"Scene.Compose.Attachment.AttachmentBroken" = "%@-a yerreẓ, ur yezmir ara +Ad d-yettwasali ɣef Mastodon."; +"Scene.Compose.Attachment.DescriptionPhoto" = "Glem-d tawlaft i wid yesɛan ugur deg yiẓri..."; +"Scene.Compose.Attachment.DescriptionVideo" = "Glem-d tavidyut i wid yesɛan ugur deg yiẓri..."; +"Scene.Compose.Attachment.Photo" = "tawlaft"; +"Scene.Compose.Attachment.Video" = "tavidyutt"; +"Scene.Compose.AutoComplete.SpaceToAdd" = "Tallunt ara yettwarnun"; +"Scene.Compose.ComposeAction" = "Sufeɣ"; +"Scene.Compose.ContentInputPlaceholder" = "Aru neɣ senteḍ ayen yellan deg wallaɣ-ik"; +"Scene.Compose.ContentWarning.Placeholder" = "Aru alɣu-inek s telqeyt da..."; +"Scene.Compose.Keyboard.AppendAttachmentEntry" = "Rnu taceqquft yeddan - %@"; +"Scene.Compose.Keyboard.DiscardPost" = "Sefsex tasuffeɣt"; +"Scene.Compose.Keyboard.PublishPost" = "Suffeɣ tasuffeɣt"; +"Scene.Compose.Keyboard.SelectVisibilityEntry" = "Fren timeẓriwt - %@"; +"Scene.Compose.Keyboard.ToggleContentWarning" = "Beddel alɣu n ugbur"; +"Scene.Compose.Keyboard.TogglePoll" = "Beddel asenqed"; +"Scene.Compose.MediaSelection.Browse" = "Snirem"; +"Scene.Compose.MediaSelection.Camera" = "Ṭṭef tawlaft"; +"Scene.Compose.MediaSelection.PhotoLibrary" = "Tanedlist n tewlaft"; +"Scene.Compose.Poll.DurationTime" = "Tangazt: %@"; +"Scene.Compose.Poll.OneDay" = "1 n wass"; +"Scene.Compose.Poll.OneHour" = "1 n wesrag"; +"Scene.Compose.Poll.OptionNumber" = "Taxtiṛt %ld"; +"Scene.Compose.Poll.SevenDays" = "7 n wussan"; +"Scene.Compose.Poll.SixHours" = "6 n yisragen"; +"Scene.Compose.Poll.ThirtyMinutes" = "30 n tesdatin"; +"Scene.Compose.Poll.ThreeDays" = "3 n wussan"; +"Scene.Compose.ReplyingToUser" = "tiririt ɣef %@"; +"Scene.Compose.Title.NewPost" = "Tasuffeɣt tamaynut"; +"Scene.Compose.Title.NewReply" = "Tiririt tamaynut"; +"Scene.Compose.Visibility.Direct" = "Imdanen i d-bedreɣ kan"; +"Scene.Compose.Visibility.Private" = "Imeḍfaṛen kan"; +"Scene.Compose.Visibility.Public" = "Azayez"; +"Scene.Compose.Visibility.Unlisted" = "War tabdert"; +"Scene.ConfirmEmail.Button.OpenEmailApp" = "Ldi asnas n yimayl"; +"Scene.ConfirmEmail.Button.Resend" = "Ales tuzna"; +"Scene.ConfirmEmail.DontReceiveEmail.Description" = "Senqed ma yella tansa-inek n imayl d tameɣut akked uspam ma yella ur t-tufiḍ ara."; +"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Ales tuzna n yimayl"; +"Scene.ConfirmEmail.DontReceiveEmail.Title" = "Senqed imayl-ik·im"; +"Scene.ConfirmEmail.OpenEmailApp.Description" = "Akken kan i ak-n-nuzen imayl. Sefqed aspam ma yella ur t-tufiḍ ara."; +"Scene.ConfirmEmail.OpenEmailApp.Mail" = "Imayl"; +"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Ldi amsaɣ n yimayl"; +"Scene.ConfirmEmail.OpenEmailApp.Title" = "Sefqed Tanaka-inek."; +"Scene.ConfirmEmail.Subtitle" = "Sit ɣef useɣwen i ak-n-uznen i wakken ad tesneqdeḍ amiḍan-ik."; +"Scene.ConfirmEmail.Title" = "Taɣawsa taneggarut."; +"Scene.Favorite.Title" = "Ismenyifen-ik·im"; +"Scene.Follower.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; +"Scene.Following.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; +"Scene.HomeTimeline.NavigationBarState.NewPosts" = "Tissufaɣ timaynutin"; +"Scene.HomeTimeline.NavigationBarState.Offline" = "Beṛṛa n tuqqna"; +"Scene.HomeTimeline.NavigationBarState.Published" = "Yettwasuffeɣ!"; +"Scene.HomeTimeline.NavigationBarState.Publishing" = "Asuffeɣ tasuffeɣt..."; +"Scene.HomeTimeline.Title" = "Agejdan"; +"Scene.Notification.Keyobard.ShowEverything" = "Sken yal taɣawsa"; +"Scene.Notification.Keyobard.ShowMentions" = "Sken tisedmirin"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "yesmenyef tasuffeɣt-ik·im"; +"Scene.Notification.NotificationDescription.FollowedYou" = "iṭṭafar-ik·ikem"; +"Scene.Notification.NotificationDescription.MentionedYou" = "yebder-ik·ikem-id"; +"Scene.Notification.NotificationDescription.PollHasEnded" = "asenqed iffuk"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "iɛawed-as asuffeɣ i tsuffeɣt-ik·im"; +"Scene.Notification.NotificationDescription.RequestToFollowYou" = "issuter aḍfar-inek"; +"Scene.Notification.Title.Everything" = "Akk"; +"Scene.Notification.Title.Mentions" = "Abdar"; +"Scene.Preview.Keyboard.ClosePreview" = "Mdel timeẓri"; +"Scene.Preview.Keyboard.ShowNext" = "Sken uḍfir"; +"Scene.Preview.Keyboard.ShowPrevious" = "Sken udfir"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Dashboard.Followers" = "imeḍfaren"; +"Scene.Profile.Dashboard.Following" = "iṭafaṛ"; +"Scene.Profile.Dashboard.Posts" = "tisuffaɣ"; +"Scene.Profile.Fields.AddRow" = "Rnu izirig"; +"Scene.Profile.Fields.Placeholder.Content" = "Agbur"; +"Scene.Profile.Fields.Placeholder.Label" = "Tabzimt"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Sentem asewḥel n %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Sewḥel amiḍan"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Sentem asgugem i %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Sgugem amiḍan"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Sentem tukksa n usgugem i %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Kkes asewḥel i umiḍan"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Sentem tukksa n usgugem i %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Kkes asgugem i umiḍan"; +"Scene.Profile.SegmentedControl.About" = "Ɣef"; +"Scene.Profile.SegmentedControl.Media" = "Amidya"; +"Scene.Profile.SegmentedControl.Posts" = "Imagraden"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "Tisuffaɣ d tririyin"; +"Scene.Profile.SegmentedControl.Replies" = "Tiririyin"; +"Scene.Register.Error.Item.Agreement" = "Amtawa"; +"Scene.Register.Error.Item.Email" = "Imayl"; +"Scene.Register.Error.Item.Locale" = "Tadigant"; +"Scene.Register.Error.Item.Password" = "Awal uffir"; +"Scene.Register.Error.Item.Reason" = "Taɣẓint"; +"Scene.Register.Error.Item.Username" = "Isem n useqdac"; +"Scene.Register.Error.Reason.Accepted" = "%@ ilaq ad yettwaqbal"; +"Scene.Register.Error.Reason.Blank" = "isra %@"; +"Scene.Register.Error.Reason.Blocked" = "%@ deg-s asaǧǧăw n yimayl ur nettusireg ara"; +"Scene.Register.Error.Reason.Inclusion" = "%@ mačči d azal yettusefraken"; +"Scene.Register.Error.Reason.Invalid" = "%@ d arameɣtu"; +"Scene.Register.Error.Reason.Reserved" = "%@ d awal uffir yettwaḥarren"; +"Scene.Register.Error.Reason.Taken" = "%@ yettwaseqdec yakan"; +"Scene.Register.Error.Reason.TooLong" = "%@ ɣezzif aṭas"; +"Scene.Register.Error.Reason.TooShort" = "%@ wezzil aṭas"; +"Scene.Register.Error.Reason.Unreachable" = "%@ ur yettban ara yella"; +"Scene.Register.Error.Special.EmailInvalid" = "Tagi mačči d tansa n yimayl tameɣtut"; +"Scene.Register.Error.Special.PasswordTooShort" = "Awal uffir wezzil aṭas (ilaq ad yesɛu ma drus 8 yisekkilen)"; +"Scene.Register.Error.Special.UsernameInvalid" = "Isem n useqdac ilaq ad yesɛu kan isekkilen igmumḍinen d wid yettujerrden"; +"Scene.Register.Error.Special.UsernameTooLong" = "Isem n useqdac ɣezzif aṭas (ur ilaq ara ad iɛeddi nnig 30 yisekkilen)"; +"Scene.Register.Input.Avatar.Delete" = "Kkes"; +"Scene.Register.Input.DisplayName.Placeholder" = "isem ara d-yettwaskanen"; +"Scene.Register.Input.Email.Placeholder" = "imayl"; +"Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "Acimi tebγiḍ ad ternuḍ iman-ik?"; +"Scene.Register.Input.Password.Accessibility.Checked" = "yettwasenqed"; +"Scene.Register.Input.Password.Accessibility.Unchecked" = "ur yettwasenqed ara"; +"Scene.Register.Input.Password.CharacterLimit" = "8 n yisekkilen"; +"Scene.Register.Input.Password.Hint" = "Awal-ik uffir yesra ma drus ṭam n yisekkilen"; +"Scene.Register.Input.Password.Placeholder" = "awal uffir"; +"Scene.Register.Input.Password.Require" = "Awal-ik uffir yesra ma drus:"; +"Scene.Register.Input.Username.DuplicatePrompt" = "Isem-ayi n umseqdac yettwaṭṭef yakan."; +"Scene.Register.Input.Username.Placeholder" = "isem n useqdac"; +"Scene.Register.Title" = "Aha ad nebdu asbadu ɣef %@"; +"Scene.Report.Content1" = "Tebɣiḍ ad ternuḍ tisuffaɣ-nniḍen ɣer uneqqis?"; +"Scene.Report.Content2" = "Yella wayen i ilaqen ad teẓren yimḍebbren ɣef uneqqis-a?"; +"Scene.Report.ReportSentTitle" = "Tanemmirt ɣef uneqqis, ad nwali deg waya."; +"Scene.Report.Reported" = "YETTWAMMEL"; +"Scene.Report.Send" = "Azen aneqis"; +"Scene.Report.SkipToSend" = "Azen s war awennit"; +"Scene.Report.Step1" = "Aḥric 1 seg 2"; +"Scene.Report.Step2" = "Aḥric 2 seg 2"; +"Scene.Report.TextPlaceholder" = "Aru neɣ senteḍ iwenniten-nniḍen"; +"Scene.Report.Title" = "Aneqqis %@"; +"Scene.Report.TitleReport" = "Aneqqis"; +"Scene.Search.Recommend.Accounts.Description" = "Ahat tebɣiḍ ad tḍefreḍ imiḍanen-a"; +"Scene.Search.Recommend.Accounts.Follow" = "Ḍfeṛ"; +"Scene.Search.Recommend.Accounts.Title" = "Imiḍanen i tzemreḍ ad tḥemmleḍ"; +"Scene.Search.Recommend.ButtonText" = "Wali akk"; +"Scene.Search.Recommend.HashTag.Description" = "Hashtags i d-ijebbden aṭas lwelha"; +"Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ yimdanen i yettmeslayen"; +"Scene.Search.Recommend.HashTag.Title" = "Ayen mucaɛen ɣef Mastodon"; +"Scene.Search.SearchBar.Cancel" = "Sefsex"; +"Scene.Search.SearchBar.Placeholder" = "Nadi hashtags d yiseqdacen"; +"Scene.Search.Searching.Clear" = "Sfeḍ"; +"Scene.Search.Searching.EmptyState.NoResults" = "Ulac igemmaḍ"; +"Scene.Search.Searching.RecentSearch" = "Inadiyen imaynuten"; +"Scene.Search.Searching.Segment.All" = "Akk"; +"Scene.Search.Searching.Segment.Hashtags" = "Ihacṭagen"; +"Scene.Search.Searching.Segment.People" = "Imdanen"; +"Scene.Search.Searching.Segment.Posts" = "Tisuffaɣ"; +"Scene.Search.Title" = "Nadi"; +"Scene.ServerPicker.Button.Category.Academia" = "akadimi"; +"Scene.ServerPicker.Button.Category.Activism" = "tinuɣmest"; +"Scene.ServerPicker.Button.Category.All" = "Akk"; +"Scene.ServerPicker.Button.Category.AllAccessiblityDescription" = "Taggayt: Akk"; +"Scene.ServerPicker.Button.Category.Art" = "taẓuri"; +"Scene.ServerPicker.Button.Category.Food" = "učči"; +"Scene.ServerPicker.Button.Category.Furry" = "furry"; +"Scene.ServerPicker.Button.Category.Games" = "uraren"; +"Scene.ServerPicker.Button.Category.General" = "amatu"; +"Scene.ServerPicker.Button.Category.Journalism" = "taɣamsa"; +"Scene.ServerPicker.Button.Category.Lgbt" = "lgbt"; +"Scene.ServerPicker.Button.Category.Music" = "aẓawan"; +"Scene.ServerPicker.Button.Category.Regional" = "amnaḍan"; +"Scene.ServerPicker.Button.Category.Tech" = "atiknikan"; +"Scene.ServerPicker.Button.SeeLess" = "Sken cwiṭ"; +"Scene.ServerPicker.Button.SeeMore" = "Wali ugar"; +"Scene.ServerPicker.EmptyState.BadNetwork" = "Tella-d tuccḍa lawan n usali n yisefka. Senqed tuqqna-ink internet."; +"Scene.ServerPicker.EmptyState.FindingServers" = "Tifin n yiqeddacen yellan..."; +"Scene.ServerPicker.EmptyState.NoResults" = "Ulac igemmaḍ"; +"Scene.ServerPicker.Input.Placeholder" = "Nadi timɣiwnin"; +"Scene.ServerPicker.Label.Category" = "TAGGAYT"; +"Scene.ServerPicker.Label.Language" = "TUTLAYT"; +"Scene.ServerPicker.Label.Users" = "ISEQDACEN"; +"Scene.ServerPicker.Subtitle" = "Fren tamɣiwent almend n wayen tḥemmleḍ, n tmurt-ik neɣ n yiswi-inek amatu."; +"Scene.ServerPicker.SubtitleExtend" = "Fren tamɣiwent almend n wayen tḥemmleḍ, n tmurt-ik neɣ n yiswi-inek amatu. Yal tamɣiwent tsedday-itt tkebbanit neɣ amdan ilelliyen."; +"Scene.ServerPicker.Title" = "Mastodon yettwaxdem i yiseqdacen deg waṭas n temɣiwnin."; +"Scene.ServerRules.Button.Confirm" = "Qebleɣ"; +"Scene.ServerRules.PrivacyPolicy" = "tasertit tabaḍnit"; +"Scene.ServerRules.Prompt" = "Mi ara tkemmleḍ, ilaq ad tqebleḍ tiwtilin n yimeẓla d tsertit tabaḍnit n %@."; +"Scene.ServerRules.Subtitle" = "Ilugan-a ttusbadun sɣur inedbalen n %@."; +"Scene.ServerRules.TermsOfService" = "tiwetlin n useqdec"; +"Scene.ServerRules.Title" = "Kra n yilugan igejdanen."; +"Scene.Settings.Footer.MastodonDescription" = "Maṣṭudun d aseɣzan s uɣbalu yeldin. Tzemreḍ ad temmleḍ uguren deg GitHub %@ (%@)"; +"Scene.Settings.Keyboard.CloseSettingsWindow" = "Mdel asfaylu n iɣewwaṛen"; +"Scene.Settings.Section.Appearance.Automatic" = "Awurman"; +"Scene.Settings.Section.Appearance.Dark" = "Yezga d aberkan"; +"Scene.Settings.Section.Appearance.Light" = "Yezga d aceεlal"; +"Scene.Settings.Section.Appearance.Title" = "Apparence"; +"Scene.Settings.Section.BoringZone.AccountSettings" = "Iɣewwaṛen n umiḍan"; +"Scene.Settings.Section.BoringZone.Privacy" = "Tasertit tabaḍnit"; +"Scene.Settings.Section.BoringZone.Terms" = "Tiwtilin n useqdec"; +"Scene.Settings.Section.BoringZone.Title" = "Tamnaḍt yessefcalen"; +"Scene.Settings.Section.LookAndFeel.Light" = "Aceɛlal"; +"Scene.Settings.Section.LookAndFeel.ReallyDark" = "D aberkan s tidet"; +"Scene.Settings.Section.LookAndFeel.SortaDark" = "D aberkan cwiya"; +"Scene.Settings.Section.LookAndFeel.Title" = "Wali, tḥalfuḍ"; +"Scene.Settings.Section.LookAndFeel.UseSystem" = "Seqdec anagraw"; +"Scene.Settings.Section.Notifications.Boosts" = "Yules asuffeɣ n tduffeɣt-iw"; +"Scene.Settings.Section.Notifications.Favorites" = "Yerna tasuffeɣt-iw ɣer yismenyafen-ines"; +"Scene.Settings.Section.Notifications.Follows" = "Yeṭṭafar-iyi"; +"Scene.Settings.Section.Notifications.Mentions" = "Ibder-iyi-d"; +"Scene.Settings.Section.Notifications.Title" = "Tilɣa"; +"Scene.Settings.Section.Notifications.Trigger.Anyone" = "yal yiwen"; +"Scene.Settings.Section.Notifications.Trigger.Follow" = "yal win ara ḍefreɣ"; +"Scene.Settings.Section.Notifications.Trigger.Follower" = "ameḍfar"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "ula yiwen"; +"Scene.Settings.Section.Notifications.Trigger.Title" = "Selɣu-yi-d mi ara"; +"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Sens ivaṭaren yettembiwilen"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Sens imujiten yettembiwilen"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.Title" = "Imenyafen"; +"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Askar aberkan n tidet"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Seqdec iminig amezwer i twaledyawt n yiseɣwan"; +"Scene.Settings.Section.SpicyZone.Clear" = "Sfeḍ takatut tuffirt n umidyat"; +"Scene.Settings.Section.SpicyZone.Signout" = "Senser"; +"Scene.Settings.Section.SpicyZone.Title" = "Tamnaḍt tamihawt"; +"Scene.Settings.Title" = "Iɣewwaṛen"; +"Scene.SuggestionAccount.FollowExplain" = "Mi ara teṭṭafareḍ albaɛḍ, ad twaliḍ tisuffaɣ-is deg usuddem-inek agejdan."; +"Scene.SuggestionAccount.Title" = "Af imdanen ara tḍefreḍ"; +"Scene.Thread.BackTitle" = "Amagrad"; +"Scene.Thread.Title" = "Tasuffeɣt sɣur %@"; +"Scene.Welcome.GetStarted" = "Aha bdu tura"; +"Scene.Welcome.LogIn" = "Qqen"; +"Scene.Welcome.Slogan" = "Izeḍwa inmettiyen +uɣalen-d ɣer ufus-ik."; +"Scene.Wizard.AccessibilityHint" = "Sin isitiyen i usefsex n umarag-a"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Beddel gar waṭas n yimiḍanen s tussda ɣezzifen ɣef tqeffalt n umaɣnu."; +"Scene.Wizard.NewInMastodon" = "Amaynut deg Maṣṭudun"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.stringsdict new file mode 100644 index 00000000..c3d72dda --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.stringsdict @@ -0,0 +1,406 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 wulɣu ur nettwaɣra + other + %ld yilɣa ur nettwaɣra + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + Talast n unekcum tɛedda %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 usekkil + other + %ld yisekkilen + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + Talast n unekcum yeqqim-d seg-s %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 usekkil + other + %ld yisekkilen + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + tasuffeɣt + other + tisuffaɣ + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 tsuffeɣt + other + %ld n tsuffaɣ + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1unurif + other + %ld yinurifen + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1uɛiwed n usuffeɣ + other + %ld n uɛiwed n usuffeɣ + + + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 tefrant + other + %ld tefranin + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1umefran + other + %ld imefranen + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 umdan i yettmeslayen + other + %ld yimdanen i yettmeslayen + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 uneḍfar + other + %ld yineḍfaren + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 uneḍfar + other + %ld yineḍfaren + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Yeqqim-d 1 useggas + other + Qqimen-d %ld yiseggasen + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 wayyur i d-yeqqimen + other + %ld wayyuren i d-yeqqimen + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Yeqqim-d 1 wass + other + Qqimen-d %ld wussan + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Yeqqim-d 1 usrag + other + Qqimen-d %ld yisragen + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 tesdat i d-yeqqimen + other + %ld tesdatin i d-yeqqimen + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 tasint i d-yeqqimen + other + %ld tsinin i d-yeqqimen + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 useggas aya + other + %ld yiseggasen aya + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 wayyur aya + other + %ld wayyuren aya + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 wass aya + other + %ld wussan aya + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 usrag aya + other + %ld yisragen aya + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 tesdat aya + other + %ld tesdatin aya + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 tasint aya + other + %ld tsinin aya + + + + diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings index 02c8be66..608163f4 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings @@ -98,6 +98,10 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Status.Actions.Menu" = "Kulîn"; "Common.Controls.Status.Actions.Reblog" = "Ji nû ve nivîsandin"; "Common.Controls.Status.Actions.Reply" = "Bersivê bide"; +"Common.Controls.Status.Actions.ShowGif" = "GIF nîşan bide"; +"Common.Controls.Status.Actions.ShowImage" = "Wêneyê nîşan bide"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Lêdera vîdyoyê nîşan bide"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Ji bo nîşandana menuyê dirêj bitikîne"; "Common.Controls.Status.Actions.Unfavorite" = "Nebijarte"; "Common.Controls.Status.Actions.Unreblog" = "Ji nû ve nivîsandinê vegere"; "Common.Controls.Status.ContentWarning" = "Hişyariya naverokê"; @@ -112,6 +116,7 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Status.Tag.Link" = "Girêdan"; "Common.Controls.Status.Tag.Mention" = "Qalkirin"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Ji bo dîtinê bitikîne"; "Common.Controls.Status.UserReblogged" = "%@ ji nû ve nivîsand"; "Common.Controls.Status.UserRepliedTo" = "Bersiv da %@"; "Common.Controls.Status.Visibility.Direct" = "Tenê bikarhênerê qalkirî dikare vê şandiyê bibîne."; @@ -217,6 +222,10 @@ girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.Preview.Keyboard.ClosePreview" = "Pêşdîtin bigire"; "Scene.Preview.Keyboard.ShowNext" = "A pêş nîşan bide"; "Scene.Preview.Keyboard.ShowPrevious" = "A paş nîşan bide"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Ducaran bitikîne bo vekirina listeyê"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Wêneya avatar serrast bike"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Wêneya avatar nîşan bide"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Wêneya paşrûyê nîşan bide"; "Scene.Profile.Dashboard.Followers" = "şopîner"; "Scene.Profile.Dashboard.Following" = "dişopîne"; "Scene.Profile.Dashboard.Posts" = "şandî"; @@ -357,6 +366,7 @@ Her kîjan rajekar be."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Min agahdar bike gava"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Avatarên anîmasyonî neçalak bike"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Emojiyên anîmasyonî neçalak bike"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Girêdanan di Mastodon de veke"; "Scene.Settings.Section.Preference.Title" = "Sazkarî"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Moda tarî ya reş a rastîn"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Ji bo vekirina girêdanan geroka berdest bi kar bîne"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.stringsdict index 8ae1b812..0fa7d821 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld ji nû ve nivîsandin + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 bersiv + other + %ld bersiv + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings index f9e04622..6a19a4bf 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings @@ -97,6 +97,10 @@ "Common.Controls.Status.Actions.Menu" = "Menu"; "Common.Controls.Status.Actions.Reblog" = "Delen"; "Common.Controls.Status.Actions.Reply" = "Reageren"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "Verwijderen uit Favorieten"; "Common.Controls.Status.Actions.Unreblog" = "Delen ongedaan maken"; "Common.Controls.Status.ContentWarning" = "Inhoudswaarschuwing"; @@ -111,6 +115,7 @@ "Common.Controls.Status.Tag.Link" = "Link"; "Common.Controls.Status.Tag.Mention" = "Vermelden"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@ gedeeld"; "Common.Controls.Status.UserRepliedTo" = "Reactie op %@"; "Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; @@ -211,6 +216,10 @@ klik op de link om uw account te bevestigen."; "Scene.Preview.Keyboard.ClosePreview" = "Voorbeeldweergave Sluiten"; "Scene.Preview.Keyboard.ShowNext" = "Volgende"; "Scene.Preview.Keyboard.ShowPrevious" = "Vorige"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; "Scene.Profile.Dashboard.Followers" = "volgers"; "Scene.Profile.Dashboard.Following" = "volgend"; "Scene.Profile.Dashboard.Posts" = "berichten"; @@ -350,6 +359,7 @@ klik op de link om uw account te bevestigen."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Stuur mij een melding wanneer"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Geanimeerde avatars uitschakelen"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Geanimeerde emojis uitschakelen"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; "Scene.Settings.Section.Preference.Title" = "Instellingen"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Echt zwarte donker uiterlijk"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Gebruik de standaard browser om links te openen"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.stringsdict index 8b6ab05c..5ae33cbe 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld gedeelde berichten + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings index aa05910c..6913d753 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings @@ -98,6 +98,10 @@ "Common.Controls.Status.Actions.Menu" = "Меню"; "Common.Controls.Status.Actions.Reblog" = "Продвинуть"; "Common.Controls.Status.Actions.Reply" = "Ответить"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "Убрать из избранного"; "Common.Controls.Status.Actions.Unreblog" = "Убрать продвижение"; "Common.Controls.Status.ContentWarning" = "Предупреждение о содержании"; @@ -112,6 +116,7 @@ "Common.Controls.Status.Tag.Link" = "Ссылка"; "Common.Controls.Status.Tag.Mention" = "Упоминание"; "Common.Controls.Status.Tag.Url" = "Ссылка"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@ продвинул(а)"; "Common.Controls.Status.UserRepliedTo" = "Ответил(а) %@"; "Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; @@ -227,6 +232,10 @@ "Scene.Preview.Keyboard.ClosePreview" = "Закрыть предпросмотр"; "Scene.Preview.Keyboard.ShowNext" = "Следующее изображение"; "Scene.Preview.Keyboard.ShowPrevious" = "Предыдущее изображение"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; "Scene.Profile.Dashboard.Followers" = "подписчики"; "Scene.Profile.Dashboard.Following" = "подписки"; "Scene.Profile.Dashboard.Posts" = "посты"; @@ -367,6 +376,7 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "Уведомлять меня, когда"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Отключить анимацию аватарок"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Отключить анимацию эмодзи"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; "Scene.Settings.Section.Preference.Title" = "Предпочтения"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Полноценно чёрный режим"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Использовать браузер по умолчанию для открытия ссылок"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.stringsdict index 96afce4e..626a10d7 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.stringsdict @@ -142,6 +142,26 @@ %ld продвинули + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + few + %ld replies + many + %ld replies + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings index 738a9ac0..07d5aa5e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings @@ -98,6 +98,10 @@ Tarkista internet-yhteytesi."; "Common.Controls.Status.Actions.Menu" = "Valikko"; "Common.Controls.Status.Actions.Reblog" = "Jaa edelleen"; "Common.Controls.Status.Actions.Reply" = "Vastaa"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "Unfavorite"; "Common.Controls.Status.Actions.Unreblog" = "Peru edelleen jako"; "Common.Controls.Status.ContentWarning" = "Sisältövaroitus"; @@ -112,6 +116,7 @@ Tarkista internet-yhteytesi."; "Common.Controls.Status.Tag.Link" = "Linkki"; "Common.Controls.Status.Tag.Mention" = "Mention"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@ jakoi edelleen"; "Common.Controls.Status.UserRepliedTo" = "Vastasi %@:lle"; "Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; @@ -216,6 +221,10 @@ uploaded to Mastodon."; "Scene.Preview.Keyboard.ClosePreview" = "Sulje esikatselu"; "Scene.Preview.Keyboard.ShowNext" = "Näytä seuraava"; "Scene.Preview.Keyboard.ShowPrevious" = "Näytä edellinen"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; "Scene.Profile.Dashboard.Followers" = "seuraajat"; "Scene.Profile.Dashboard.Following" = "seurataan"; "Scene.Profile.Dashboard.Posts" = "julkaisut"; @@ -356,6 +365,7 @@ mikä tahansa palvelin."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Ilmoita minulle, kun"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Poista käytöstä animoidut avatarit"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Poista käytöstä animoidut emojit"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; "Scene.Settings.Section.Preference.Title" = "Lisäasetukset"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Todellinen mustan tumma tila"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Käytä oletusselainta linkkien avaamiseen"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.stringsdict index eec977a6..43231214 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.stringsdict @@ -114,6 +114,22 @@ %ld edelleen jakoa + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings index c79bb681..de50842f 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings @@ -98,6 +98,10 @@ "Common.Controls.Status.Actions.Menu" = "เมนู"; "Common.Controls.Status.Actions.Reblog" = "ดัน"; "Common.Controls.Status.Actions.Reply" = "ตอบกลับ"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "เลิกชื่นชอบ"; "Common.Controls.Status.Actions.Unreblog" = "เลิกทำการดัน"; "Common.Controls.Status.ContentWarning" = "คำเตือนเนื้อหา"; @@ -112,6 +116,7 @@ "Common.Controls.Status.Tag.Link" = "ลิงก์"; "Common.Controls.Status.Tag.Mention" = "กล่าวถึง"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@ ได้ดัน"; "Common.Controls.Status.UserRepliedTo" = "ตอบกลับ %@"; "Common.Controls.Status.Visibility.Direct" = "เฉพาะผู้ใช้ที่กล่าวถึงเท่านั้นที่สามารถเห็นโพสต์นี้"; @@ -216,6 +221,10 @@ "Scene.Preview.Keyboard.ClosePreview" = "ปิดตัวอย่าง"; "Scene.Preview.Keyboard.ShowNext" = "แสดงถัดไป"; "Scene.Preview.Keyboard.ShowPrevious" = "แสดงก่อนหน้า"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; "Scene.Profile.Dashboard.Followers" = "ผู้ติดตาม"; "Scene.Profile.Dashboard.Following" = "กำลังติดตาม"; "Scene.Profile.Dashboard.Posts" = "โพสต์"; @@ -355,6 +364,7 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "แจ้งเตือนฉันเมื่อ"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "ปิดใช้งานภาพประจำตัวแบบเคลื่อนไหว"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "ปิดใช้งานอีโมจิแบบเคลื่อนไหว"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; "Scene.Settings.Section.Preference.Title" = "การกำหนดลักษณะ"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "โหมดมืดดำสนิท"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "ใช้เบราว์เซอร์เริ่มต้นเพื่อเปิดลิงก์"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict index 8971821f..3895c399 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict @@ -100,6 +100,20 @@ %ld การดัน + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings new file mode 100644 index 00000000..95eef33b --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings @@ -0,0 +1,385 @@ +"Common.Alerts.BlockDomain.BlockEntireDomain" = "Chặn máy chủ"; +"Common.Alerts.BlockDomain.Title" = "Bạn thật sự muốn ẩn toàn bộ nội dung từ %@? Sẽ hợp lý hơn nếu bạn chỉ chặn hoặc ẩn một vài tài khoản cụ thể. Ẩn toàn bộ nội dung từ máy chủ sẽ khiến bạn không còn thấy nội dung từ máy chủ đó ở bất kỳ nơi nào, kể cả thông báo. Người theo dõi bạn từ máy chủ đó cũng sẽ bị xóa luôn."; +"Common.Alerts.CleanCache.Message" = "Đã xóa %@ bộ nhớ đệm."; +"Common.Alerts.CleanCache.Title" = "Xóa bộ nhớ đệm"; +"Common.Alerts.Common.PleaseTryAgain" = "Vui lòng thử lại."; +"Common.Alerts.Common.PleaseTryAgainLater" = "Vui lòng thử lại sau."; +"Common.Alerts.DeletePost.Message" = "Bạn có chắc muốn xóa tút này không?"; +"Common.Alerts.DeletePost.Title" = "Xóa tút"; +"Common.Alerts.DiscardPostContent.Message" = "Xác nhận bỏ qua nội dung tút đã viết."; +"Common.Alerts.DiscardPostContent.Title" = "Hủy bản nháp"; +"Common.Alerts.EditProfileFailure.Message" = "Không thể chỉnh sửa trang cá nhân. Vui lòng thử lại."; +"Common.Alerts.EditProfileFailure.Title" = "Lỗi chỉnh sửa trang cá nhân"; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Không thể đính kèm nhiều video."; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Không thể đính kèm video cùng với hình ảnh."; +"Common.Alerts.PublishPostFailure.Message" = "Không thể đăng tút. +Vui lòng kiểm tra kết nối mạng."; +"Common.Alerts.PublishPostFailure.Title" = "Đăng tút không thành công"; +"Common.Alerts.SavePhotoFailure.Message" = "Vui lòng cho phép quyền truy cập thư viện hình ảnh để lưu hình ảnh về máy."; +"Common.Alerts.SavePhotoFailure.Title" = "Lưu hình ảnh không thành công"; +"Common.Alerts.ServerError.Title" = "Lỗi máy chủ"; +"Common.Alerts.SignOut.Confirm" = "Đăng xuất"; +"Common.Alerts.SignOut.Message" = "Bạn có chắc muốn đăng xuất không?"; +"Common.Alerts.SignOut.Title" = "Đăng xuất"; +"Common.Alerts.SignUpFailure.Title" = "Đăng ký không thành công"; +"Common.Alerts.VoteFailure.PollEnded" = "Cuộc bình chọn đã kết thúc"; +"Common.Alerts.VoteFailure.Title" = "Bình chọn không thành công"; +"Common.Controls.Actions.Add" = "Thêm"; +"Common.Controls.Actions.Back" = "Quay lại"; +"Common.Controls.Actions.BlockDomain" = "Chặn %@"; +"Common.Controls.Actions.Cancel" = "Hủy bỏ"; +"Common.Controls.Actions.Compose" = "Viết tút"; +"Common.Controls.Actions.Confirm" = "Xác nhận"; +"Common.Controls.Actions.Continue" = "Tiếp tục"; +"Common.Controls.Actions.CopyPhoto" = "Sao chép ảnh"; +"Common.Controls.Actions.Delete" = "Xóa"; +"Common.Controls.Actions.Discard" = "Bỏ qua"; +"Common.Controls.Actions.Done" = "Xong"; +"Common.Controls.Actions.Edit" = "Sửa"; +"Common.Controls.Actions.FindPeople" = "Đề xuất theo dõi"; +"Common.Controls.Actions.ManuallySearch" = "Tự tìm kiếm thủ công"; +"Common.Controls.Actions.Next" = "Kế tiếp"; +"Common.Controls.Actions.Ok" = "OK"; +"Common.Controls.Actions.Open" = "Mở"; +"Common.Controls.Actions.OpenInBrowser" = "Mở trong trình duyệt"; +"Common.Controls.Actions.OpenInSafari" = "Mở bằng Safari"; +"Common.Controls.Actions.Preview" = "Xem trước"; +"Common.Controls.Actions.Previous" = "Trước đó"; +"Common.Controls.Actions.Remove" = "Xóa"; +"Common.Controls.Actions.Reply" = "Trả lời"; +"Common.Controls.Actions.ReportUser" = "Báo cáo %@"; +"Common.Controls.Actions.Save" = "Lưu"; +"Common.Controls.Actions.SavePhoto" = "Lưu ảnh"; +"Common.Controls.Actions.SeeMore" = "Xem thêm"; +"Common.Controls.Actions.Settings" = "Cài đặt"; +"Common.Controls.Actions.Share" = "Chia sẻ"; +"Common.Controls.Actions.SharePost" = "Chia sẻ tút"; +"Common.Controls.Actions.ShareUser" = "Chia sẻ %@"; +"Common.Controls.Actions.SignIn" = "Đăng nhập"; +"Common.Controls.Actions.SignUp" = "Đăng ký"; +"Common.Controls.Actions.Skip" = "Bỏ qua"; +"Common.Controls.Actions.TakePhoto" = "Chụp ảnh"; +"Common.Controls.Actions.TryAgain" = "Thử lại"; +"Common.Controls.Actions.UnblockDomain" = "Bỏ chặn %@"; +"Common.Controls.Friendship.Block" = "Chặn"; +"Common.Controls.Friendship.BlockDomain" = "Chặn %@"; +"Common.Controls.Friendship.BlockUser" = "Chặn %@"; +"Common.Controls.Friendship.Blocked" = "Đã chặn"; +"Common.Controls.Friendship.EditInfo" = "Chỉnh sửa"; +"Common.Controls.Friendship.Follow" = "Theo dõi"; +"Common.Controls.Friendship.Following" = "Đang theo dõi"; +"Common.Controls.Friendship.Mute" = "Ẩn"; +"Common.Controls.Friendship.MuteUser" = "Ẩn %@"; +"Common.Controls.Friendship.Muted" = "Đã ẩn"; +"Common.Controls.Friendship.Pending" = "Đang chờ"; +"Common.Controls.Friendship.Request" = "Yêu cầu"; +"Common.Controls.Friendship.Unblock" = "Bỏ chặn"; +"Common.Controls.Friendship.UnblockUser" = "Bỏ chặn %@"; +"Common.Controls.Friendship.Unmute" = "Bỏ ẩn"; +"Common.Controls.Friendship.UnmuteUser" = "Bỏ ẩn %@"; +"Common.Controls.Keyboard.Common.ComposeNewPost" = "Viết tút mới"; +"Common.Controls.Keyboard.Common.OpenSettings" = "Mở cài đặt"; +"Common.Controls.Keyboard.Common.ShowFavorites" = "Hiện lượt thích"; +"Common.Controls.Keyboard.Common.SwitchToTab" = "Chuyển thành %@"; +"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Tới phần tiếp theo"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Tới phần trước"; +"Common.Controls.Keyboard.Timeline.NextStatus" = "Tút sau"; +"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Mở trang người viết tút"; +"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Mở trang người đăng lại tút"; +"Common.Controls.Keyboard.Timeline.OpenStatus" = "Mở tút"; +"Common.Controls.Keyboard.Timeline.PreviewImage" = "Xem trước hình ảnh"; +"Common.Controls.Keyboard.Timeline.PreviousStatus" = "Tút trước"; +"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Trả lời tút"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Chọn nội dung ẩn"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Chọn thích tút"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Chọn đăng lại tút"; +"Common.Controls.Status.Actions.Favorite" = "Thích"; +"Common.Controls.Status.Actions.Hide" = "Ẩn"; +"Common.Controls.Status.Actions.Menu" = "Menu"; +"Common.Controls.Status.Actions.Reblog" = "Đăng lại"; +"Common.Controls.Status.Actions.Reply" = "Trả lời"; +"Common.Controls.Status.Actions.ShowGif" = "Hiển thị GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Hiển thị hình ảnh"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Hiện trình phát video"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Nhấn giữ để hiện menu"; +"Common.Controls.Status.Actions.Unfavorite" = "Bỏ thích"; +"Common.Controls.Status.Actions.Unreblog" = "Hủy đăng lại"; +"Common.Controls.Status.ContentWarning" = "Nội dung ẩn"; +"Common.Controls.Status.MediaContentWarning" = "Nhấn để hiển thị"; +"Common.Controls.Status.Poll.Closed" = "Kết thúc"; +"Common.Controls.Status.Poll.Vote" = "Bình chọn"; +"Common.Controls.Status.ShowPost" = "Xem tút"; +"Common.Controls.Status.ShowUserProfile" = "Xem trang cá nhân"; +"Common.Controls.Status.Tag.Email" = "Email"; +"Common.Controls.Status.Tag.Emoji" = "Emoji"; +"Common.Controls.Status.Tag.Hashtag" = "Hashtag"; +"Common.Controls.Status.Tag.Link" = "Liên kết"; +"Common.Controls.Status.Tag.Mention" = "Nhắc đến"; +"Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Nhấn để hiển thị"; +"Common.Controls.Status.UserReblogged" = "%@ đăng lại"; +"Common.Controls.Status.UserRepliedTo" = "Trả lời %@"; +"Common.Controls.Status.Visibility.Direct" = "Chỉ người được nhắc đến có thể thấy tút."; +"Common.Controls.Status.Visibility.Private" = "Chỉ người theo dõi của họ có thể thấy tút này."; +"Common.Controls.Status.Visibility.PrivateFromMe" = "Chỉ người theo dõi tôi có thể thấy tút này."; +"Common.Controls.Status.Visibility.Unlisted" = "Ai cũng thấy tút này nhưng không hiện trên bảng tin máy chủ."; +"Common.Controls.Tabs.Home" = "Bảng tin"; +"Common.Controls.Tabs.Notification" = "Thông báo"; +"Common.Controls.Tabs.Profile" = "Trang cá nhân"; +"Common.Controls.Tabs.Search" = "Tìm kiếm"; +"Common.Controls.Timeline.Filtered" = "Bộ lọc"; +"Common.Controls.Timeline.Header.BlockedWarning" = "Bạn không thể xem trang người này +cho tới khi họ bỏ chặn bạn."; +"Common.Controls.Timeline.Header.BlockingWarning" = "Bạn không thể xem trang người này +cho tới khi bạn bỏ chặn họ. +Họ sẽ thấy trang của bạn như thế này."; +"Common.Controls.Timeline.Header.NoStatusFound" = "Không tìm thấy tút"; +"Common.Controls.Timeline.Header.SuspendedWarning" = "Người dùng đã bị vô hiệu hóa."; +"Common.Controls.Timeline.Header.UserBlockedWarning" = "Bạn không thể xem trang %@ +cho tới khi họ bỏ chặn bạn."; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "Bạn không thể xem trang %@ +cho tới khi bạn bỏ chặn họ. +Họ sẽ thấy trang của bạn như thế này."; +"Common.Controls.Timeline.Header.UserSuspendedWarning" = "%@ đã bị vô hiệu hóa."; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Tải tút chưa đọc"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Đang tải tút chưa đọc..."; +"Common.Controls.Timeline.Loader.ShowMoreReplies" = "Xem lượt trả lời"; +"Common.Controls.Timeline.Timestamp.Now" = "Vừa xong"; +"Scene.AccountList.AddAccount" = "Thêm tài khoản"; +"Scene.AccountList.DismissAccountSwitcher" = "Bỏ qua chuyển đổi tài khoản"; +"Scene.AccountList.TabBarHint" = "Đang dùng tài khoản: %@. Nhấn hai lần và giữ để đổi sang tài khoản khác"; +"Scene.Compose.Accessibility.AppendAttachment" = "Thêm media"; +"Scene.Compose.Accessibility.AppendPoll" = "Tạo bình chọn"; +"Scene.Compose.Accessibility.CustomEmojiPicker" = "Chọn emoji"; +"Scene.Compose.Accessibility.DisableContentWarning" = "Tắt nội dung ẩn"; +"Scene.Compose.Accessibility.EnableContentWarning" = "Bật nội dung ẩn"; +"Scene.Compose.Accessibility.PostVisibilityMenu" = "Menu hiển thị tút"; +"Scene.Compose.Accessibility.RemovePoll" = "Xóa bình chọn"; +"Scene.Compose.Attachment.AttachmentBroken" = "%@ này bị lỗi và không thể +tải lên Mastodon."; +"Scene.Compose.Attachment.DescriptionPhoto" = "Mô tả hình ảnh cho người khiếm thị..."; +"Scene.Compose.Attachment.DescriptionVideo" = "Mô tả video cho người khiếm thị..."; +"Scene.Compose.Attachment.Photo" = "ảnh"; +"Scene.Compose.Attachment.Video" = "video"; +"Scene.Compose.AutoComplete.SpaceToAdd" = "Khoảng cách để thêm"; +"Scene.Compose.ComposeAction" = "Đăng"; +"Scene.Compose.ContentInputPlaceholder" = "Cho thế giới biết bạn đang nghĩ gì"; +"Scene.Compose.ContentWarning.Placeholder" = "Viết nội dung ẩn của bạn ở đây..."; +"Scene.Compose.Keyboard.AppendAttachmentEntry" = "Thêm media - %@"; +"Scene.Compose.Keyboard.DiscardPost" = "Hủy đăng tút"; +"Scene.Compose.Keyboard.PublishPost" = "Đăng tút"; +"Scene.Compose.Keyboard.SelectVisibilityEntry" = "Thay đổi quyền riêng tư - %@"; +"Scene.Compose.Keyboard.ToggleContentWarning" = "Mở nội dung ẩn"; +"Scene.Compose.Keyboard.TogglePoll" = "Mở bình chọn"; +"Scene.Compose.MediaSelection.Browse" = "Chọn"; +"Scene.Compose.MediaSelection.Camera" = "Chụp ảnh"; +"Scene.Compose.MediaSelection.PhotoLibrary" = "Thư viện hình ảnh"; +"Scene.Compose.Poll.DurationTime" = "Thời gian: %@"; +"Scene.Compose.Poll.OneDay" = "1 ngày"; +"Scene.Compose.Poll.OneHour" = "1 giờ"; +"Scene.Compose.Poll.OptionNumber" = "Lựa chọn %ld"; +"Scene.Compose.Poll.SevenDays" = "7 ngày"; +"Scene.Compose.Poll.SixHours" = "6 giờ"; +"Scene.Compose.Poll.ThirtyMinutes" = "30 phút"; +"Scene.Compose.Poll.ThreeDays" = "3 ngày"; +"Scene.Compose.ReplyingToUser" = "trả lời đến %@"; +"Scene.Compose.Title.NewPost" = "Viết tút"; +"Scene.Compose.Title.NewReply" = "Viết trả lời"; +"Scene.Compose.Visibility.Direct" = "Chỉ người được nhắc đến"; +"Scene.Compose.Visibility.Private" = "Riêng tư"; +"Scene.Compose.Visibility.Public" = "Công khai"; +"Scene.Compose.Visibility.Unlisted" = "Hạn chế"; +"Scene.ConfirmEmail.Button.OpenEmailApp" = "Mở ứng dụng email"; +"Scene.ConfirmEmail.Button.Resend" = "Gửi lại"; +"Scene.ConfirmEmail.DontReceiveEmail.Description" = "Kiểm tra địa chỉ email của bạn đúng chưa hoặc có bị chuyển vào thư rác."; +"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Gửi lại email"; +"Scene.ConfirmEmail.DontReceiveEmail.Title" = "Kiểm tra email"; +"Scene.ConfirmEmail.OpenEmailApp.Description" = "Chúng tôi vừa gửi email cho bạn. Kiểm tra thư rác nếu bạn không thấy."; +"Scene.ConfirmEmail.OpenEmailApp.Mail" = "Email"; +"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Mở ứng dụng email"; +"Scene.ConfirmEmail.OpenEmailApp.Title" = "Kiểm tra hộp thư của bạn."; +"Scene.ConfirmEmail.Subtitle" = "Nhấn vào liên kết chúng tôi gửi qua email để xác thực tài khoản."; +"Scene.ConfirmEmail.Title" = "Còn điều này nữa."; +"Scene.Favorite.Title" = "Lượt thích"; +"Scene.Follower.Footer" = "Không hiển thị người theo dõi từ máy chủ khác."; +"Scene.Following.Footer" = "Không hiển thị người bạn theo dõi từ máy chủ khác."; +"Scene.HomeTimeline.NavigationBarState.NewPosts" = "Đọc những tút mới"; +"Scene.HomeTimeline.NavigationBarState.Offline" = "Ngoại tuyến"; +"Scene.HomeTimeline.NavigationBarState.Published" = "Đã đăng!"; +"Scene.HomeTimeline.NavigationBarState.Publishing" = "Đang đăng tút..."; +"Scene.HomeTimeline.Title" = "Bảng tin"; +"Scene.Notification.Keyobard.ShowEverything" = "Hiện mọi thứ"; +"Scene.Notification.Keyobard.ShowMentions" = "Hiện lượt nhắc"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "thích tút của bạn"; +"Scene.Notification.NotificationDescription.FollowedYou" = "đã theo dõi bạn"; +"Scene.Notification.NotificationDescription.MentionedYou" = "nhắc đến bạn"; +"Scene.Notification.NotificationDescription.PollHasEnded" = "cuộc bình chọn đã kết thúc"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "đăng lại tút của bạn"; +"Scene.Notification.NotificationDescription.RequestToFollowYou" = "yêu cầu theo dõi bạn"; +"Scene.Notification.Title.Everything" = "Mọi thứ"; +"Scene.Notification.Title.Mentions" = "Lượt nhắc đến"; +"Scene.Preview.Keyboard.ClosePreview" = "Đóng xem trước"; +"Scene.Preview.Keyboard.ShowNext" = "Hiện kế tiếp"; +"Scene.Preview.Keyboard.ShowPrevious" = "Hiện trước đó"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Nhấn hai lần để mở danh sách"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Sửa ảnh đại diện"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Hiển thị ảnh đại diện"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Hiển thị ảnh bìa"; +"Scene.Profile.Dashboard.Followers" = "người theo dõi"; +"Scene.Profile.Dashboard.Following" = "theo dõi"; +"Scene.Profile.Dashboard.Posts" = "tút"; +"Scene.Profile.Fields.AddRow" = "Thêm hàng"; +"Scene.Profile.Fields.Placeholder.Content" = "Nội dung"; +"Scene.Profile.Fields.Placeholder.Label" = "Nhãn"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Xác nhận chặn %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Chặn người dùng"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Xác nhận ẩn %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Ẩn người dùng"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Xác nhận bỏ chặn %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Bỏ chặn người dùng"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Xác nhận bỏ ẩn %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Bỏ ẩn người dùng"; +"Scene.Profile.SegmentedControl.About" = "Giới thiệu"; +"Scene.Profile.SegmentedControl.Media" = "Media"; +"Scene.Profile.SegmentedControl.Posts" = "Tút"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "Tút và trả lời"; +"Scene.Profile.SegmentedControl.Replies" = "Trả lời"; +"Scene.Register.Error.Item.Agreement" = "Thoả thuận"; +"Scene.Register.Error.Item.Email" = "Email"; +"Scene.Register.Error.Item.Locale" = "Cục bộ"; +"Scene.Register.Error.Item.Password" = "Mật khẩu"; +"Scene.Register.Error.Item.Reason" = "Lý do"; +"Scene.Register.Error.Item.Username" = "Tên người dùng"; +"Scene.Register.Error.Reason.Accepted" = "%@ phải được đồng ý"; +"Scene.Register.Error.Reason.Blank" = "%@ là bắt buộc"; +"Scene.Register.Error.Reason.Blocked" = "%@ dùng dịch vụ email bị cấm"; +"Scene.Register.Error.Reason.Inclusion" = "%@ chứa ký tự không được hỗ trợ"; +"Scene.Register.Error.Reason.Invalid" = "%@ không hợp lệ"; +"Scene.Register.Error.Reason.Reserved" = "%@ là một từ khóa hạn chế"; +"Scene.Register.Error.Reason.Taken" = "%@ đã tồn tại"; +"Scene.Register.Error.Reason.TooLong" = "%@ quá dài"; +"Scene.Register.Error.Reason.TooShort" = "%@ quá ngắn"; +"Scene.Register.Error.Reason.Unreachable" = "%@ không tồn tại"; +"Scene.Register.Error.Special.EmailInvalid" = "Đây không phải là một địa chỉ email khả dụng"; +"Scene.Register.Error.Special.PasswordTooShort" = "Mật khẩu của bạn quá ngắn, phải có ít nhất 8 ký tự"; +"Scene.Register.Error.Special.UsernameInvalid" = "Tên người dùng chỉ có thể chứa các ký tự chữ và số và dấu gạch dưới"; +"Scene.Register.Error.Special.UsernameTooLong" = "Tên người dùng không thể dài hơn 30 ký tự"; +"Scene.Register.Input.Avatar.Delete" = "Xóa"; +"Scene.Register.Input.DisplayName.Placeholder" = "tên hiển thị"; +"Scene.Register.Input.Email.Placeholder" = "email"; +"Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "Vì sao bạn muốn tham gia?"; +"Scene.Register.Input.Password.Accessibility.Checked" = "đã ổn"; +"Scene.Register.Input.Password.Accessibility.Unchecked" = "chưa ổn"; +"Scene.Register.Input.Password.CharacterLimit" = "8 ký tự"; +"Scene.Register.Input.Password.Hint" = "Mật khẩu của bạn phải dài tối thiểu 8 ký tự"; +"Scene.Register.Input.Password.Placeholder" = "mật khẩu"; +"Scene.Register.Input.Password.Require" = "Mật khẩu phải tối thiểu:"; +"Scene.Register.Input.Username.DuplicatePrompt" = "Tên người dùng đã tồn tại."; +"Scene.Register.Input.Username.Placeholder" = "tên người dùng"; +"Scene.Register.Title" = "Hãy để tôi đăng ký trên %@"; +"Scene.Report.Content1" = "Bạn muốn thêm tút nào vào báo cáo nữa không?"; +"Scene.Report.Content2" = "Kiểm duyệt viên cần biết gì về báo cáo này?"; +"Scene.Report.ReportSentTitle" = "Cảm ơn đã báo cáo, chúng tôi sẽ xem xét kỹ."; +"Scene.Report.Reported" = "ĐÃ BÁO CÁO"; +"Scene.Report.Send" = "Gửi báo cáo"; +"Scene.Report.SkipToSend" = "Gửi không ghi chú"; +"Scene.Report.Step1" = "Bước 1 trong 2"; +"Scene.Report.Step2" = "Bước 2 trong 2"; +"Scene.Report.TextPlaceholder" = "Nhập hoặc bổ sung chú thích"; +"Scene.Report.Title" = "Báo cáo %@"; +"Scene.Report.TitleReport" = "Báo cáo"; +"Scene.Search.Recommend.Accounts.Description" = "Bạn có thể muốn theo dõi những người này"; +"Scene.Search.Recommend.Accounts.Follow" = "Theo dõi"; +"Scene.Search.Recommend.Accounts.Title" = "Những người bạn có thể thích"; +"Scene.Search.Recommend.ButtonText" = "Xem tất cả"; +"Scene.Search.Recommend.HashTag.Description" = "Những hashtag đang được sử dụng nhiều nhất"; +"Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ người đang thảo luận"; +"Scene.Search.Recommend.HashTag.Title" = "Xu hướng trên Mastodon"; +"Scene.Search.SearchBar.Cancel" = "Hủy bỏ"; +"Scene.Search.SearchBar.Placeholder" = "Tìm hashtag và người dùng"; +"Scene.Search.Searching.Clear" = "Xóa"; +"Scene.Search.Searching.EmptyState.NoResults" = "Không có kết quả"; +"Scene.Search.Searching.RecentSearch" = "Tìm kiếm gần đây"; +"Scene.Search.Searching.Segment.All" = "Tất cả"; +"Scene.Search.Searching.Segment.Hashtags" = "Hashtag"; +"Scene.Search.Searching.Segment.People" = "Người dùng"; +"Scene.Search.Searching.Segment.Posts" = "Tút"; +"Scene.Search.Title" = "Tìm kiếm"; +"Scene.ServerPicker.Button.Category.Academia" = "học thuật"; +"Scene.ServerPicker.Button.Category.Activism" = "hoạt động xã hội"; +"Scene.ServerPicker.Button.Category.All" = "Toàn bộ"; +"Scene.ServerPicker.Button.Category.AllAccessiblityDescription" = "Phân loại: Toàn bộ"; +"Scene.ServerPicker.Button.Category.Art" = "nghệ thuật"; +"Scene.ServerPicker.Button.Category.Food" = "ăn uống"; +"Scene.ServerPicker.Button.Category.Furry" = "furry"; +"Scene.ServerPicker.Button.Category.Games" = "trò chơi"; +"Scene.ServerPicker.Button.Category.General" = "chung"; +"Scene.ServerPicker.Button.Category.Journalism" = "tin tức"; +"Scene.ServerPicker.Button.Category.Lgbt" = "lgbt"; +"Scene.ServerPicker.Button.Category.Music" = "âm nhạc"; +"Scene.ServerPicker.Button.Category.Regional" = "khu vực"; +"Scene.ServerPicker.Button.Category.Tech" = "công nghệ"; +"Scene.ServerPicker.Button.SeeLess" = "Ẩn bớt"; +"Scene.ServerPicker.Button.SeeMore" = "Nhiều hơn"; +"Scene.ServerPicker.EmptyState.BadNetwork" = "Đã xảy ra lỗi. Hãy thử lại hoặc kiểm tra kết nối internet của bạn."; +"Scene.ServerPicker.EmptyState.FindingServers" = "Đang tìm máy chủ hoạt động..."; +"Scene.ServerPicker.EmptyState.NoResults" = "Không có kết quả"; +"Scene.ServerPicker.Input.Placeholder" = "Tìm cộng đồng"; +"Scene.ServerPicker.Label.Category" = "PHÂN LOẠI"; +"Scene.ServerPicker.Label.Language" = "NGÔN NGỮ"; +"Scene.ServerPicker.Label.Users" = "NGƯỜI DÙNG"; +"Scene.ServerPicker.Subtitle" = "Chọn một cộng đồng dựa theo sở thích, tôn giáo, hoặc ý muốn của bạn."; +"Scene.ServerPicker.SubtitleExtend" = "Chọn một cộng đồng dựa theo sở thích, tôn giáo, hoặc ý muốn của bạn. Mỗi cộng đồng có thể được vận hành bởi một tổ chức độc lập hoặc một cá nhân."; +"Scene.ServerPicker.Title" = "Mastodon gồm nhiều cộng đồng với nhiều thành viên khác nhau."; +"Scene.ServerRules.Button.Confirm" = "Tôi đồng ý"; +"Scene.ServerRules.PrivacyPolicy" = "chính sách bảo mật"; +"Scene.ServerRules.Prompt" = "Tiếp tục nghĩa là bạn đồng ý điều khoản dịch vụ và chính sách bảo mật của %@."; +"Scene.ServerRules.Subtitle" = "Được ban hành và áp dụng bởi quản trị viên %@"; +"Scene.ServerRules.TermsOfService" = "điều khoản dịch vụ"; +"Scene.ServerRules.Title" = "Quy tắc máy chủ."; +"Scene.Settings.Footer.MastodonDescription" = "Mastodon là phần mềm mã nguồn mở. Bạn có thể báo lỗi trên GitHub tại %@ (%@)"; +"Scene.Settings.Keyboard.CloseSettingsWindow" = "Đóng cửa sổ cài đặt"; +"Scene.Settings.Section.Appearance.Automatic" = "Tự động"; +"Scene.Settings.Section.Appearance.Dark" = "Tối"; +"Scene.Settings.Section.Appearance.Light" = "Sáng"; +"Scene.Settings.Section.Appearance.Title" = "Giao diện"; +"Scene.Settings.Section.BoringZone.AccountSettings" = "Cài đặt tài khoản"; +"Scene.Settings.Section.BoringZone.Privacy" = "Chính sách bảo mật"; +"Scene.Settings.Section.BoringZone.Terms" = "Điều khoản dịch vụ"; +"Scene.Settings.Section.BoringZone.Title" = "Nhàm chán"; +"Scene.Settings.Section.LookAndFeel.Light" = "Sáng"; +"Scene.Settings.Section.LookAndFeel.ReallyDark" = "Tối Mạnh"; +"Scene.Settings.Section.LookAndFeel.SortaDark" = "Tối Nhẹ"; +"Scene.Settings.Section.LookAndFeel.Title" = "Giao diện"; +"Scene.Settings.Section.LookAndFeel.UseSystem" = "Mặc định hệ thống"; +"Scene.Settings.Section.Notifications.Boosts" = "Đăng lại tút của tôi"; +"Scene.Settings.Section.Notifications.Favorites" = "Thích tút của tôi"; +"Scene.Settings.Section.Notifications.Follows" = "Theo dõi tôi"; +"Scene.Settings.Section.Notifications.Mentions" = "Nhắc đến tôi"; +"Scene.Settings.Section.Notifications.Title" = "Thông báo"; +"Scene.Settings.Section.Notifications.Trigger.Anyone" = "ai đó"; +"Scene.Settings.Section.Notifications.Trigger.Follow" = "người tôi theo dõi"; +"Scene.Settings.Section.Notifications.Trigger.Follower" = "người theo dõi"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "không một ai"; +"Scene.Settings.Section.Notifications.Trigger.Title" = "Thông báo khi"; +"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Tắt ảnh đại diện GIF"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Tắt emoji dạng GIF"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Mở liên kết trong Mastodon"; +"Scene.Settings.Section.Preference.Title" = "Chung"; +"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Chế độ tối chân thật"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Dùng trình duyệt mặc định"; +"Scene.Settings.Section.SpicyZone.Clear" = "Xóa bộ nhớ đệm"; +"Scene.Settings.Section.SpicyZone.Signout" = "Đăng xuất"; +"Scene.Settings.Section.SpicyZone.Title" = "Thú vị"; +"Scene.Settings.Title" = "Cài đặt"; +"Scene.SuggestionAccount.FollowExplain" = "Khi theo dõi ai đó, bạn sẽ thấy tút của họ trong bảng tin."; +"Scene.SuggestionAccount.Title" = "Đề xuất theo dõi"; +"Scene.Thread.BackTitle" = "Tút"; +"Scene.Thread.Title" = "Tút của %@"; +"Scene.Welcome.GetStarted" = "Bắt đầu"; +"Scene.Welcome.LogIn" = "Đăng nhập"; +"Scene.Welcome.Slogan" = "Mạng xã hội +do bạn kiểm soát."; +"Scene.Wizard.AccessibilityHint" = "Nhấn hai lần để bỏ qua"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Chuyển đổi giữa nhiều tài khoản bằng cách đè giữ nút tài khoản."; +"Scene.Wizard.NewInMastodon" = "Mới trên Mastodon"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.stringsdict new file mode 100644 index 00000000..71ba1951 --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.stringsdict @@ -0,0 +1,356 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld thông báo chưa đọc + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + Giới hạn nhập tối đa %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld ký tự + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + Giới hạn nhập còn lại %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld ký tự + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + tút + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld tút + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld lượt thích + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld đăng lại + + + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld trả lời + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld bình chọn + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld người bình chọn + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld người đang thảo luận + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld đang theo dõi + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld người theo dõi + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld năm còn lại + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld tháng còn lại + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld ngày còn lại + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld giờ còn lại + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld phút còn lại + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld giây còn lại + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld năm trước + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld tháng trước + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld ngày trước + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ldh + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ldm + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %lds + + + + diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings index 7ad984f1..f4a90541 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings @@ -98,6 +98,10 @@ "Common.Controls.Status.Actions.Menu" = "菜单"; "Common.Controls.Status.Actions.Reblog" = "转发"; "Common.Controls.Status.Actions.Reply" = "回复"; +"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "取消喜欢"; "Common.Controls.Status.Actions.Unreblog" = "取消转发"; "Common.Controls.Status.ContentWarning" = "内容警告"; @@ -112,6 +116,7 @@ "Common.Controls.Status.Tag.Link" = "链接"; "Common.Controls.Status.Tag.Mention" = "提及"; "Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@ 转发"; "Common.Controls.Status.UserRepliedTo" = "回复给 %@"; "Common.Controls.Status.Visibility.Direct" = "只有提到的用户才能看到此帖子。"; @@ -217,6 +222,10 @@ "Scene.Preview.Keyboard.ClosePreview" = "关闭预览"; "Scene.Preview.Keyboard.ShowNext" = "显示下一个"; "Scene.Preview.Keyboard.ShowPrevious" = "显示前一个"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; "Scene.Profile.Dashboard.Followers" = "关注者"; "Scene.Profile.Dashboard.Following" = "正在关注"; "Scene.Profile.Dashboard.Posts" = "帖子"; @@ -357,6 +366,7 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "提示通知来自"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "禁用动画头像"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "禁用动画表情"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; "Scene.Settings.Section.Preference.Title" = "偏好"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "纯黑模式"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "使用默认浏览器打开链接"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict index 12b8b5f6..41890383 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict @@ -100,6 +100,20 @@ %ld 条转发 + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld replies + + plural.count.vote NSStringLocalizedFormatKey From 09a29742ef7f3c5d1973f16a1943ac83d72b76a7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 1 Apr 2022 22:44:01 +0200 Subject: [PATCH 100/188] New translations Localizable.stringsdict (Italian) --- .../StringsConvertor/input/it_IT/Localizable.stringsdict | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict b/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict index 48222f42..c35837ba 100644 --- a/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict @@ -189,9 +189,9 @@ NSStringFormatValueTypeKey ld one - 1 seguace + 1 following other - %ld following + %ld stanno seguendo plural.count.follower @@ -205,7 +205,7 @@ NSStringFormatValueTypeKey ld one - 1 follower + 1 seguace other %ld followers From 3e37b125543a8d872d30fd4a63fd480bf1e9621a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 1 Apr 2022 23:53:25 +0200 Subject: [PATCH 101/188] New translations app.json (Italian) --- .../StringsConvertor/input/it_IT/app.json | 330 +++++++++--------- 1 file changed, 165 insertions(+), 165 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/app.json b/Localization/StringsConvertor/input/it_IT/app.json index c839cbef..e1e24ec7 100644 --- a/Localization/StringsConvertor/input/it_IT/app.json +++ b/Localization/StringsConvertor/input/it_IT/app.json @@ -80,71 +80,71 @@ "preview": "Anteprima", "share": "Condividi", "share_user": "Condividi %s", - "share_post": "Share Post", - "open_in_safari": "Open in Safari", - "open_in_browser": "Open in Browser", - "find_people": "Find people to follow", - "manually_search": "Manually search instead", - "skip": "Skip", - "reply": "Reply", - "report_user": "Report %s", - "block_domain": "Block %s", - "unblock_domain": "Unblock %s", - "settings": "Settings", - "delete": "Delete" + "share_post": "Condividi il post", + "open_in_safari": "Apri su Safari", + "open_in_browser": "Apri nel browser", + "find_people": "Trova persone da seguire", + "manually_search": "Cerca manualmente invece", + "skip": "Salta", + "reply": "Rispondi", + "report_user": "Segnala %s", + "block_domain": "Blocca %s", + "unblock_domain": "Sblocca %s", + "settings": "Impostazioni", + "delete": "Elimina" }, "tabs": { - "home": "Home", - "search": "Search", - "notification": "Notification", - "profile": "Profile" + "home": "Inizio", + "search": "Cerca", + "notification": "Notifiche", + "profile": "Profilo" }, "keyboard": { "common": { - "switch_to_tab": "Switch to %s", - "compose_new_post": "Compose New Post", - "show_favorites": "Show Favorites", - "open_settings": "Open Settings" + "switch_to_tab": "Passa a %s", + "compose_new_post": "Componi un nuovo post", + "show_favorites": "Mostra preferiti", + "open_settings": "Apri Impostazioni" }, "timeline": { - "previous_status": "Previous Post", - "next_status": "Next Post", - "open_status": "Open Post", - "open_author_profile": "Open Author's Profile", - "open_reblogger_profile": "Open Reblogger's Profile", - "reply_status": "Reply to Post", - "toggle_reblog": "Toggle Reblog on Post", - "toggle_favorite": "Toggle Favorite on Post", - "toggle_content_warning": "Toggle Content Warning", - "preview_image": "Preview Image" + "previous_status": "Post precedente", + "next_status": "Post successivo", + "open_status": "Apri il post", + "open_author_profile": "Apri il profilo dell'autore", + "open_reblogger_profile": "Apri il profilo di chi ha condiviso", + "reply_status": "Rispondi al post", + "toggle_reblog": "Attiva/Disattiva condivisione sul post", + "toggle_favorite": "Attiva/Disattiva preferito nel post", + "toggle_content_warning": "Attiva/Disattiva avvertimento contenuti", + "preview_image": "Anteprima immagine" }, "segmented_control": { - "previous_section": "Previous Section", - "next_section": "Next Section" + "previous_section": "Sezione precedente", + "next_section": "Sezione successiva" } }, "status": { - "user_reblogged": "%s reblogged", - "user_replied_to": "Replied to %s", - "show_post": "Show Post", - "show_user_profile": "Show user profile", - "content_warning": "Content Warning", - "media_content_warning": "Tap anywhere to reveal", - "tap_to_reveal": "Tap to reveal", + "user_reblogged": "%s hanno condiviso", + "user_replied_to": "Rispondi a %s", + "show_post": "Mostra il post", + "show_user_profile": "Mostra il profilo dell'utente", + "content_warning": "Avviso sul contenuto", + "media_content_warning": "Tocca ovunque per rivelare", + "tap_to_reveal": "Tocca per rivelare", "poll": { - "vote": "Vote", - "closed": "Closed" + "vote": "Vota", + "closed": "Chiuso" }, "actions": { - "reply": "Reply", - "reblog": "Reblog", - "unreblog": "Undo reblog", - "favorite": "Favorite", - "unfavorite": "Unfavorite", - "menu": "Menu", - "hide": "Hide", - "show_image": "Show image", - "show_gif": "Show GIF", + "reply": "Rispondi", + "reblog": "Condivisione", + "unreblog": "Annulla condivisione", + "favorite": "Preferito", + "unfavorite": "Non preferito", + "menu": "Menù", + "hide": "Nascondi", + "show_image": "Mostra immagine", + "show_gif": "Mostra GIF", "show_video_player": "Mostra lettore video", "tap_then_hold_to_show_menu": "Tocca quindi tieni premuto per mostrare il menu" }, @@ -219,88 +219,88 @@ "all_accessiblity_description": "Categoria: Tutti", "academia": "accademia", "activism": "attivismo", - "food": "food", - "furry": "furry", - "games": "games", - "general": "general", - "journalism": "journalism", + "food": "cibo", + "furry": "peloso", + "games": "giochi", + "general": "generale", + "journalism": "giornalismo", "lgbt": "lgbt", - "regional": "regional", - "art": "art", - "music": "music", - "tech": "tech" + "regional": "locale", + "art": "arte", + "music": "musica", + "tech": "tecnologia" }, - "see_less": "See Less", - "see_more": "See More" + "see_less": "Vedi meno", + "see_more": "Vedi di più" }, "label": { - "language": "LANGUAGE", - "users": "USERS", - "category": "CATEGORY" + "language": "LINGUA", + "users": "UTENTI", + "category": "CATEGORIA" }, "input": { - "placeholder": "Search communities" + "placeholder": "Cerca comunità" }, "empty_state": { - "finding_servers": "Finding available servers...", - "bad_network": "Something went wrong while loading the data. Check your internet connection.", - "no_results": "No results" + "finding_servers": "Ricerca server disponibili...", + "bad_network": "Qualcosa è andato storto durante il caricamento dei dati. Controlla la tua connessione internet.", + "no_results": "Nessun risultato" } }, "register": { - "title": "Let’s get you set up on %s", + "title": "Facciamo in modo che sia configurato il %s", "input": { "avatar": { - "delete": "Delete" + "delete": "Elimina" }, "username": { - "placeholder": "username", - "duplicate_prompt": "This username is taken." + "placeholder": "nome utente", + "duplicate_prompt": "Questo nome utente è già stato preso." }, "display_name": { - "placeholder": "display name" + "placeholder": "visualizza nome" }, "email": { "placeholder": "email" }, "password": { "placeholder": "password", - "require": "Your password needs at least:", - "character_limit": "8 characters", + "require": "La tua password ha bisogno di almeno:", + "character_limit": "8 caratteri", "accessibility": { - "checked": "checked", - "unchecked": "unchecked" + "checked": "verificato", + "unchecked": "non verificato" }, - "hint": "Your password needs at least eight characters" + "hint": "La tua password deve essere di almeno 8 caratteri" }, "invite": { - "registration_user_invite_request": "Why do you want to join?" + "registration_user_invite_request": "Perché vuoi unirti?" } }, "error": { "item": { - "username": "Username", + "username": "Nome utente", "email": "Email", "password": "Password", - "agreement": "Agreement", + "agreement": "Accordo", "locale": "Locale", - "reason": "Reason" + "reason": "Motivo" }, "reason": { - "blocked": "%s contains a disallowed email provider", - "unreachable": "%s does not seem to exist", - "taken": "%s is already in use", - "reserved": "%s is a reserved keyword", - "accepted": "%s must be accepted", - "blank": "%s is required", - "invalid": "%s is invalid", - "too_long": "%s is too long", - "too_short": "%s is too short", - "inclusion": "%s is not a supported value" + "blocked": "%s contiene un provider email non consentito", + "unreachable": "%s non sembra esistere", + "taken": "%s è già in uso", + "reserved": "%s è una parola chiave riservata", + "accepted": "%s deve essere accettato", + "blank": "%s è richiesto", + "invalid": "%s non è valido", + "too_long": "%s è troppo lungo", + "too_short": "%s è troppo corto", + "inclusion": "%s non è un valore supportato" }, "special": { - "username_invalid": "Username must only contain alphanumeric characters and underscores", - "username_too_long": "Username is too long (can’t be longer than 30 characters)", + "username_invalid": "Il nome utente deve contenere solo caratteri alfanumerici e trattini bassi", + "username_too_long": "Il nome utente è troppo lungo (non può essere più lungo di 30 caratteri)", "email_invalid": "Questo non è un indirizzo email valido", "password_too_short": "La password è troppo corta (deve contenere almeno 8 caratteri)" } @@ -384,97 +384,97 @@ "visibility": { "public": "Pubblico", "unlisted": "Non elencato", - "private": "Followers only", - "direct": "Only people I mention" + "private": "Solo i seguaci", + "direct": "Solo le persone che menziono" }, "auto_complete": { - "space_to_add": "Space to add" + "space_to_add": "Spazio da aggiungere" }, "accessibility": { - "append_attachment": "Add Attachment", - "append_poll": "Add Poll", - "remove_poll": "Remove Poll", - "custom_emoji_picker": "Custom Emoji Picker", - "enable_content_warning": "Enable Content Warning", - "disable_content_warning": "Disable Content Warning", - "post_visibility_menu": "Post Visibility Menu" + "append_attachment": "Aggiungi allegato", + "append_poll": "Aggiungi sondaggio", + "remove_poll": "Elimina sondaggio", + "custom_emoji_picker": "Selettore Emoji personalizzato", + "enable_content_warning": "Abilita avvertimento contenuti", + "disable_content_warning": "Disabilita avviso di contenuti", + "post_visibility_menu": "Menu di visibilità del post" }, "keyboard": { - "discard_post": "Discard Post", - "publish_post": "Publish Post", - "toggle_poll": "Toggle Poll", - "toggle_content_warning": "Toggle Content Warning", - "append_attachment_entry": "Add Attachment - %s", - "select_visibility_entry": "Select Visibility - %s" + "discard_post": "Scarta post", + "publish_post": "Pubblica il post", + "toggle_poll": "Attiva/Disattiva Sondaggio", + "toggle_content_warning": "Attiva/Disattiva avviso contenuti", + "append_attachment_entry": "Aggiungi allegato - %s", + "select_visibility_entry": "Seleziona visibilità - %s" } }, "profile": { "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "posts": "post", + "following": "seguendo", + "followers": "seguaci" }, "fields": { - "add_row": "Add Row", + "add_row": "Aggiungi riga", "placeholder": { - "label": "Label", - "content": "Content" + "label": "Etichetta", + "content": "Contenuto" } }, "segmented_control": { - "posts": "Posts", - "replies": "Replies", - "posts_and_replies": "Posts and Replies", + "posts": "Post", + "replies": "Risposte", + "posts_and_replies": "Post e risposte", "media": "Media", - "about": "About" + "about": "Info su" }, "relationship_action_alert": { "confirm_mute_user": { - "title": "Mute Account", - "message": "Confirm to mute %s" + "title": "Silenzia account", + "message": "Confermi di silenziare %s" }, "confirm_unmute_user": { - "title": "Unmute Account", - "message": "Confirm to unmute %s" + "title": "Riattiva account", + "message": "Confermi di riattivare %s" }, "confirm_block_user": { - "title": "Block Account", - "message": "Confirm to block %s" + "title": "Blocca account", + "message": "Confermi di bloccare %s" }, "confirm_unblock_user": { - "title": "Unblock Account", - "message": "Confirm to unblock %s" + "title": "Sblocca account", + "message": "Conferma per sbloccare %s" } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", - "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "show_avatar_image": "Mostra immagine avatar", + "edit_avatar_image": "Modifica immagine avatar", + "show_banner_image": "Mostra immagine banner", + "double_tap_to_open_the_list": "Doppio tocco per aprire la lista" } }, "follower": { - "footer": "Followers from other servers are not displayed." + "footer": "I seguaci da altri server non vengono visualizzati." }, "following": { - "footer": "Follows from other servers are not displayed." + "footer": "I follow da altri server non vengono visualizzati." }, "search": { - "title": "Search", + "title": "Cerca", "search_bar": { - "placeholder": "Search hashtags and users", - "cancel": "Cancel" + "placeholder": "Cerca hashtag e utenti", + "cancel": "Annulla" }, "recommend": { - "button_text": "See All", + "button_text": "Vedi tutto", "hash_tag": { - "title": "Trending on Mastodon", - "description": "Hashtags that are getting quite a bit of attention", - "people_talking": "%s people are talking" + "title": "Di tendenza su Mastodon", + "description": "Hashtag che stanno ottenendo un bel po' di attenzione", + "people_talking": "%s persone ne parlano" }, "accounts": { - "title": "Accounts you might like", - "description": "You may like to follow these accounts", + "title": "Account che potrebbero piacerti", + "description": "Potresti voler seguire questi account", "follow": "Segui" } }, @@ -559,44 +559,44 @@ "title": "La zona boring", "account_settings": "Impostazioni account", "terms": "Termini di servizio", - "privacy": "Privacy Policy" + "privacy": "Politica sulla Privacy" }, "spicy_zone": { - "title": "The Spicy Zone", - "clear": "Clear Media Cache", - "signout": "Sign Out" + "title": "La zona piccante", + "clear": "Cancella la cache multimediale", + "signout": "Esci" } }, "footer": { - "mastodon_description": "Mastodon is open source software. You can report issues on GitHub at %s (%s)" + "mastodon_description": "Mastodon è un software open source. Puoi segnalare problemi su GitHub a %s (%s)" }, "keyboard": { - "close_settings_window": "Close Settings Window" + "close_settings_window": "Chiudi la finestra Impostazioni" } }, "report": { - "title_report": "Report", - "title": "Report %s", - "step1": "Step 1 of 2", - "step2": "Step 2 of 2", - "content1": "Are there any other posts you’d like to add to the report?", - "content2": "Is there anything the moderators should know about this report?", - "report_sent_title": "Thanks for reporting, we’ll look into this.", - "send": "Send Report", - "skip_to_send": "Send without comment", - "text_placeholder": "Type or paste additional comments", - "reported": "REPORTED" + "title_report": "Segnala", + "title": "Segnala %s", + "step1": "Fase 1 di 2", + "step2": "Fase 2 di 2", + "content1": "Ci sono altri post che vorresti aggiungere alla segnalazione?", + "content2": "C'è qualcosa che i moderatori dovrebbero sapere su questa segnalazione?", + "report_sent_title": "Grazie per la segnalazione, esamineremo questo aspetto.", + "send": "Invia segnalazione", + "skip_to_send": "Invia senza commento", + "text_placeholder": "Digita o incolla commenti aggiuntivi", + "reported": "SEGNALATO" }, "preview": { "keyboard": { - "close_preview": "Close Preview", - "show_next": "Show Next", - "show_previous": "Show Previous" + "close_preview": "Chiudi anteprima", + "show_next": "Mostra successivo", + "show_previous": "Mostra precedente" } }, "account_list": { - "tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher", - "dismiss_account_switcher": "Dismiss Account Switcher", + "tab_bar_hint": "Profilo corrente selezionato: %s. Doppio tocco e tieni premuto per mostrare il cambio account", + "dismiss_account_switcher": "Ignora il cambio account", "add_account": "Add Account" }, "wizard": { From ead027491a04b73cb44c57e898318337cebd5e3c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 1 Apr 2022 23:53:26 +0200 Subject: [PATCH 102/188] New translations Localizable.stringsdict (Italian) --- .../input/it_IT/Localizable.stringsdict | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict b/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict index c35837ba..775a161d 100644 --- a/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict @@ -207,7 +207,7 @@ one 1 seguace other - %ld followers + %ld seguaci date.year.left @@ -221,9 +221,9 @@ NSStringFormatValueTypeKey ld one - 1 year left + 1 anno rimasto other - %ld years left + %ld anni rimasti date.month.left @@ -237,9 +237,9 @@ NSStringFormatValueTypeKey ld one - 1 months left + 1 mese rimasto other - %ld months left + %ld mesi rimasti date.day.left @@ -253,9 +253,9 @@ NSStringFormatValueTypeKey ld one - 1 day left + 1 giorno rimasto other - %ld days left + %ld giorni rimasti date.hour.left @@ -269,9 +269,9 @@ NSStringFormatValueTypeKey ld one - 1 hour left + 1 ora rimasta other - %ld hours left + %ld ore rimaste date.minute.left @@ -285,9 +285,9 @@ NSStringFormatValueTypeKey ld one - 1 minute left + 1 minuto rimasto other - %ld minutes left + %ld minuti rimasti date.second.left @@ -301,9 +301,9 @@ NSStringFormatValueTypeKey ld one - 1 second left + 1 secondo rimasto other - %ld seconds left + %ld secondi rimasti date.year.ago.abbr @@ -317,9 +317,9 @@ NSStringFormatValueTypeKey ld one - 1y ago + 1 anno fa other - %ldy ago + %ld anni fa date.month.ago.abbr @@ -333,9 +333,9 @@ NSStringFormatValueTypeKey ld one - 1M ago + 1 mese fa other - %ldM ago + %ld mesi fa date.day.ago.abbr @@ -349,9 +349,9 @@ NSStringFormatValueTypeKey ld one - 1d ago + 1 giorno fa other - %ldd ago + %ld giorni fa date.hour.ago.abbr @@ -365,9 +365,9 @@ NSStringFormatValueTypeKey ld one - 1h ago + 1 ora fa other - %ldh ago + %ld ore fa date.minute.ago.abbr @@ -381,9 +381,9 @@ NSStringFormatValueTypeKey ld one - 1m ago + 1 minuto fa other - %ldm ago + %ld minuti fa date.second.ago.abbr @@ -397,9 +397,9 @@ NSStringFormatValueTypeKey ld one - 1s ago + 1 secondo fa other - %lds ago + %ld secondi fa From 8e0ff398cf3006794be7e93c1e6a8e07184d611b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 1 Apr 2022 23:53:27 +0200 Subject: [PATCH 103/188] New translations Intents.strings (Italian) --- .../Intents/input/it_IT/Intents.strings | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/it_IT/Intents.strings b/Localization/StringsConvertor/Intents/input/it_IT/Intents.strings index 6877490b..d26aef14 100644 --- a/Localization/StringsConvertor/Intents/input/it_IT/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/it_IT/Intents.strings @@ -1,51 +1,51 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "Pubblica su Mastodon"; -"751xkl" = "Text Content"; +"751xkl" = "Contenuto testuale"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "Pubblica su Mastodon"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Quale contenuto postare?"; -"HdGikU" = "Posting failed"; +"HdGikU" = "Pubblicazione non riuscita"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "Motivo del fallimento"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Invia post con contenuto testuale"; -"RxSqsb" = "Post"; +"RxSqsb" = "Pubblica"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "Pubblica ${content} su Mastodon"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "Pubblica"; "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "Visibilità"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "Visibilità del post"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Ci sono ${count} opzioni corrispondenti a 'Pubblico'."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Ci sono ${count} opzioni corrispondenti a ‘Solo Seguaci’."; -"ayoYEb-dYQ5NN" = "${content}, Public"; +"ayoYEb-dYQ5NN" = "${content}, Pubblico"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}, Solo seguaci"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "Pubblica su Mastodon"; -"dYQ5NN" = "Public"; +"dYQ5NN" = "Pubblico"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "Solo i seguaci"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "Pubblicazione fallita. ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "Post inviato con successo."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "Solo per confermare, volevi ‘Pubblico’?"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "Solo per confermare, volevi 'Solo seguaci'?"; "rM6dvp" = "URL"; -"ryJLwG" = "Post was sent successfully. "; +"ryJLwG" = "Post inviato con successo. "; From 52ae555bc4fe55df729bd1a4549be1b20e1334ec Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 1 Apr 2022 23:53:28 +0200 Subject: [PATCH 104/188] New translations Intents.stringsdict (Italian) --- .../Intents/input/it_IT/Intents.stringsdict | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Localization/StringsConvertor/Intents/input/it_IT/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/it_IT/Intents.stringsdict index 18422c77..75d98a9e 100644 --- a/Localization/StringsConvertor/Intents/input/it_IT/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/it_IT/Intents.stringsdict @@ -5,7 +5,7 @@ There are ${count} options matching ‘${content}’. - 2 NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${content}’. + Ci sono %#@count_option@ corrispondenti a «${content}». count_option NSStringFormatSpecTypeKey @@ -13,15 +13,15 @@ NSStringFormatValueTypeKey %ld one - 1 option + 1 opzione other - %ld options + %ld opzioni There are ${count} options matching ‘${visibility}’. NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${visibility}’. + Ci sono %#@count_option@ corrispondenti a «${visibility}». count_option NSStringFormatSpecTypeKey @@ -29,9 +29,9 @@ NSStringFormatValueTypeKey %ld one - 1 option + 1 opzione other - %ld options + %ld opzioni From d63fd1476103c6fb6e670b6814fbd9b4e5b39f16 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 2 Apr 2022 01:19:13 +0200 Subject: [PATCH 105/188] New translations app.json (Italian) --- Localization/StringsConvertor/input/it_IT/app.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/app.json b/Localization/StringsConvertor/input/it_IT/app.json index e1e24ec7..7d0ef92f 100644 --- a/Localization/StringsConvertor/input/it_IT/app.json +++ b/Localization/StringsConvertor/input/it_IT/app.json @@ -597,12 +597,12 @@ "account_list": { "tab_bar_hint": "Profilo corrente selezionato: %s. Doppio tocco e tieni premuto per mostrare il cambio account", "dismiss_account_switcher": "Ignora il cambio account", - "add_account": "Add Account" + "add_account": "Aggiungi account" }, "wizard": { - "new_in_mastodon": "New in Mastodon", - "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", - "accessibility_hint": "Double tap to dismiss this wizard" + "new_in_mastodon": "Nuovo su Mastodon", + "multiple_account_switch_intro_description": "Passa tra più account tenendo premuto il pulsante del profilo.", + "accessibility_hint": "Doppio tocco per eliminare questa procedura guidata" } } } \ No newline at end of file From f4812e7c573ab910fc135601780a9378670b2b9a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 2 Apr 2022 01:19:14 +0200 Subject: [PATCH 106/188] New translations Localizable.stringsdict (Italian) --- .../StringsConvertor/input/it_IT/Localizable.stringsdict | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict b/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict index 775a161d..71098060 100644 --- a/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/it_IT/Localizable.stringsdict @@ -95,7 +95,7 @@ one 1 preferito other - %ld favorites + %ld preferiti plural.count.reblog From 31614d4b86b032a80fccce336493512937ae4920 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 2 Apr 2022 04:21:08 +0200 Subject: [PATCH 107/188] New translations app.json (Vietnamese) --- Localization/StringsConvertor/input/vi_VN/app.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/vi_VN/app.json b/Localization/StringsConvertor/input/vi_VN/app.json index eafd513b..74a4bdfe 100644 --- a/Localization/StringsConvertor/input/vi_VN/app.json +++ b/Localization/StringsConvertor/input/vi_VN/app.json @@ -28,8 +28,8 @@ } }, "edit_profile_failure": { - "title": "Lỗi chỉnh sửa trang cá nhân", - "message": "Không thể chỉnh sửa trang cá nhân. Vui lòng thử lại." + "title": "Lỗi chỉnh sửa hồ sơ", + "message": "Không thể chỉnh sửa hồ sơ. Vui lòng thử lại." }, "sign_out": { "title": "Đăng xuất", @@ -97,7 +97,7 @@ "home": "Bảng tin", "search": "Tìm kiếm", "notification": "Thông báo", - "profile": "Trang cá nhân" + "profile": "Trang hồ sơ" }, "keyboard": { "common": { @@ -127,7 +127,7 @@ "user_reblogged": "%s đăng lại", "user_replied_to": "Trả lời %s", "show_post": "Xem tút", - "show_user_profile": "Xem trang cá nhân", + "show_user_profile": "Xem trang hồ sơ", "content_warning": "Nội dung ẩn", "media_content_warning": "Nhấn để hiển thị", "tap_to_reveal": "Nhấn để hiển thị", From c7c75f633dc9181438586691660e7a6f6df8b761 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 2 Apr 2022 10:35:08 +0200 Subject: [PATCH 108/188] New translations app.json (Thai) --- .../StringsConvertor/input/th_TH/app.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index 183f9cfc..3efdbb39 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -130,7 +130,7 @@ "show_user_profile": "แสดงโปรไฟล์ผู้ใช้", "content_warning": "คำเตือนเนื้อหา", "media_content_warning": "แตะที่ใดก็ตามเพื่อเปิดเผย", - "tap_to_reveal": "Tap to reveal", + "tap_to_reveal": "แตะเพื่อเปิดเผย", "poll": { "vote": "ลงคะแนน", "closed": "ปิดแล้ว" @@ -143,10 +143,10 @@ "unfavorite": "เลิกชื่นชอบ", "menu": "เมนู", "hide": "ซ่อน", - "show_image": "Show image", - "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_image": "แสดงภาพ", + "show_gif": "แสดง GIF", + "show_video_player": "แสดงตัวเล่นวิดีโอ", + "tap_then_hold_to_show_menu": "แตะค้างไว้เพื่อแสดงเมนู" }, "tag": { "url": "URL", @@ -447,10 +447,10 @@ } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", - "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "show_avatar_image": "แสดงภาพประจำตัว", + "edit_avatar_image": "แก้ไขภาพประจำตัว", + "show_banner_image": "แสดงภาพแบนเนอร์", + "double_tap_to_open_the_list": "แตะสองครั้งเพื่อเปิดรายการ" } }, "follower": { @@ -553,7 +553,7 @@ "disable_avatar_animation": "ปิดใช้งานภาพประจำตัวแบบเคลื่อนไหว", "disable_emoji_animation": "ปิดใช้งานอีโมจิแบบเคลื่อนไหว", "using_default_browser": "ใช้เบราว์เซอร์เริ่มต้นเพื่อเปิดลิงก์", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "เปิดลิงก์ใน Mastodon" }, "boring_zone": { "title": "โซนน่าเบื่อ", From c373d225a335ec5ed80f7a0da481fccf09276495 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 2 Apr 2022 10:35:09 +0200 Subject: [PATCH 109/188] New translations Localizable.stringsdict (Thai) --- .../StringsConvertor/input/th_TH/Localizable.stringsdict | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict index 3895c399..8ae8feb7 100644 --- a/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/th_TH/Localizable.stringsdict @@ -111,7 +111,7 @@ NSStringFormatValueTypeKey ld other - %ld replies + %ld การตอบกลับ plural.count.vote From a93fcdaa46f3c695c96c668e3e2dc1fd9f682071 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 2 Apr 2022 15:40:21 +0200 Subject: [PATCH 110/188] New translations Localizable.stringsdict (Arabic) --- .../input/ar_SA/Localizable.stringsdict | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index 32782f1c..41b852e7 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -519,15 +519,15 @@ zero مُنذُ لَحظة one - مُنذُ يوم + مُنذُ %ldي two - مُنذُ يومين + مُنذُ %ldي few - مُنذُ %ld أيام + مُنذُ %ldي many - مُنذُ %ld يومًا + مُنذُ %ldي other - مُنذُ %ld يوم + مُنذُ %ldي date.hour.ago.abbr @@ -543,15 +543,15 @@ zero مُنذُ لَحظة one - مُنذُ ساعة + مُنذُ %ldس two - مُنذُ ساعتين + مُنذُ %ldس few - مُنذُ %ld ساعات + مُنذُ %ldس many - مُنذُ %ld ساعةًَ + مُنذُ %ldس other - مُنذُ %ld ساعة + مُنذُ %ldس date.minute.ago.abbr From c9a346619617349085fe25fe13bd654038445b85 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 2 Apr 2022 16:38:41 +0200 Subject: [PATCH 111/188] New translations Localizable.stringsdict (Arabic) --- .../input/ar_SA/Localizable.stringsdict | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict index 41b852e7..c2f64172 100644 --- a/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar_SA/Localizable.stringsdict @@ -471,15 +471,15 @@ zero مُنذُ لَحظة one - مُنذُ سنة + مُنذُ %ldع two - مُنذُ سنتين + مُنذُ %ldع few - مُنذُ %ld سنين + مُنذُ %ldع many - مُنذُ %ld سنةً + مُنذُ %ldع other - مُنذُ %ld سنة + مُنذُ %ldع date.month.ago.abbr @@ -495,15 +495,15 @@ zero مُنذُ لَحظة one - مُنذُ شهر + مُنذُ %ldش two - مُنذُ شهرين + مُنذُ %ldش few - مُنذُ %ld أشهُر + مُنذُ %ldش many - مُنذُ %ld شهرًا + مُنذُ %ldش other - مُنذُ %ld شهر + مُنذُ %ldش date.day.ago.abbr @@ -567,15 +567,15 @@ zero مُنذُ لَحظة one - مُنذُ دقيقة + مُنذُ %ldد two - مُنذُ دقيقتان + مُنذُ %ldد few - مُنذُ %ld دقائق + مُنذُ %ldد many - مُنذُ %ld دقيقةً + مُنذُ %ldد other - مُنذُ %ld دقيقة + مُنذُ %ldد date.second.ago.abbr @@ -591,15 +591,15 @@ zero مُنذُ لَحظة one - مُنذُ ثانية + مُنذُ %ldث two - مُنذُ ثانيتين + مُنذُ %ldث few - مُنذُ %ld ثوان + مُنذُ %ldث many - مُنذُ %ld ثانية + مُنذُ %ldث other - مُنذُ %ld ثانية + مُنذُ %ldث From 8d1939c659780c95d64abd91adffb57fe4b237bf Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 4 Apr 2022 21:15:28 +0200 Subject: [PATCH 112/188] New translations app.json (Catalan) --- .../StringsConvertor/input/ca_ES/app.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index 1c73b917..d2a67819 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -41,11 +41,11 @@ "block_entire_domain": "Bloquejar Domini" }, "save_photo_failure": { - "title": "Desa l'Error de la Foto", + "title": "Error al Desar la Foto", "message": "Activa el permís d'accés a la biblioteca de fotos per desar-la." }, "delete_post": { - "title": "Estàs segur que vols suprimir aquesta publicació?", + "title": "Esborrar Publicació", "message": "Estàs segur que vols suprimir aquesta publicació?" }, "clean_cache": { @@ -83,7 +83,7 @@ "share_post": "Compartir Publicació", "open_in_safari": "Obrir a Safari", "open_in_browser": "Obre al navegador", - "find_people": "Busca persones per seguir", + "find_people": "Busca persones a seguir", "manually_search": "Cerca manualment a canvi", "skip": "Omet", "reply": "Respon", @@ -110,16 +110,16 @@ "previous_status": "Publicació anterior", "next_status": "Publicació següent", "open_status": "Obre la publicació", - "open_author_profile": "Obre el perfil de l'autor", - "open_reblogger_profile": "Obre el perfil del impulsor", - "reply_status": "Respon a la publicació", - "toggle_reblog": "Commuta l'impuls de la publicació", - "toggle_favorite": "Commuta el Favorit de la publicació", + "open_author_profile": "Obre el Perfil de l'Autor", + "open_reblogger_profile": "Obre el Perfil del Impulsor", + "reply_status": "Respon a la Publicació", + "toggle_reblog": "Commuta l'Impuls de la Publicació", + "toggle_favorite": "Commuta el Favorit de la Publicació", "toggle_content_warning": "Commuta l'Avís de Contingut", "preview_image": "Vista prèvia de l'Imatge" }, "segmented_control": { - "previous_section": "Secció anterior", + "previous_section": "Secció Anterior", "next_section": "Secció següent" } }, From 7fa7934fd5b234ab2fb7e7f81c0b54d65d790515 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 4 Apr 2022 22:21:22 +0200 Subject: [PATCH 113/188] New translations app.json (Catalan) --- .../StringsConvertor/input/ca_ES/app.json | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index d2a67819..b7ff6735 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -120,16 +120,16 @@ }, "segmented_control": { "previous_section": "Secció Anterior", - "next_section": "Secció següent" + "next_section": "Secció Següent" } }, "status": { "user_reblogged": "%s ha impulsat", "user_replied_to": "Ha respòs a %s", - "show_post": "Mostra la publicació", + "show_post": "Mostra la Publicació", "show_user_profile": "Mostra el perfil de l'usuari", "content_warning": "Advertència de Contingut", - "media_content_warning": "Toca qualsevol lloc per mostrar", + "media_content_warning": "Toca qualsevol lloc per a mostrar", "tap_to_reveal": "Toca per a mostrar", "poll": { "vote": "Vota", @@ -187,15 +187,15 @@ "now": "Ara" }, "loader": { - "load_missing_posts": "Carrega les publicacions que falten", - "loading_missing_posts": "Carregant les publicacions que falten...", + "load_missing_posts": "Carrega les publicacions faltants", + "loading_missing_posts": "Carregant les publicacions faltants...", "show_more_replies": "Mostra més respostes" }, "header": { "no_status_found": "No s'ha trobat cap publicació", "blocking_warning": "No pots veure el perfil d'aquest usuari\n fins que el desbloquegis.\nEl teu perfil els sembla així.", "user_blocking_warning": "No pots veure el perfil de %s\n fins que el desbloquegis.\nEl teu perfil els sembla així.", - "blocked_warning": "No pots veure el perfil d'aquest usuari\n fins que et desbloquegi.", + "blocked_warning": "No pots veure el perfil d'aquest usuari\nfins que et desbloquegi.", "user_blocked_warning": "No pots veure el perfil de %s\n fins que et desbloquegi.", "suspended_warning": "Aquest usuari ha estat suspès.", "user_suspended_warning": "El compte de %s ha estat suspès." @@ -210,7 +210,7 @@ "log_in": "Inicia sessió" }, "server_picker": { - "title": "Tria un servidor,\nqualsevol servidor.", + "title": "Mastodon està fet d'usuaris en diferents comunitats.", "subtitle": "Tria una comunitat segons els teus interessos, regió o una de propòsit general.", "subtitle_extend": "Tria una comunitat segons els teus interessos, regió o una de propòsit general. Cada comunitat és operada per una organització totalment independent o individualment.", "button": { @@ -271,7 +271,7 @@ "checked": "verificat", "unchecked": "no verificat" }, - "hint": "La teva contrasenya ha de tenir com a mínim buit caràcters" + "hint": "La teva contrasenya ha de tenir com a mínim vuit caràcters" }, "invite": { "registration_user_invite_request": "Perquè vols unir-te?" @@ -299,7 +299,7 @@ "inclusion": "%s no és un valor suportat" }, "special": { - "username_invalid": "El nom d'usuari només ha de contenir caràcters alfanumèrics i guions baixos", + "username_invalid": "El nom d'usuari ha de contenir només caràcters alfanumèrics i guions baixos", "username_too_long": "El nom d'usuari és massa llarg (no pot ser més llarg de 30 caràcters)", "email_invalid": "Aquesta no és una adreça de correu electrònic vàlida", "password_too_short": "La contrasenya és massa curta (ha de tenir 8 caràcters com a mínim)" @@ -318,7 +318,7 @@ }, "confirm_email": { "title": "Una última cosa.", - "subtitle": "Acabem d'enviar un correu electrònic a %s,\ntoca l'enllaç per a confirmar el teu compte.", + "subtitle": "Toca l'enllaç del correu electrònic que t'hem enviat per a confirmar el teu compte.", "button": { "open_email_app": "Obre l'aplicació de correu", "resend": "Reenvia" @@ -543,7 +543,7 @@ "anyone": "algú", "follower": "un seguidor", "follow": "a qualsevol que segueixi", - "noone": "algú", + "noone": "ningú", "title": "Notifica'm quan" } }, From 4c6fb7c36927ea1bb3cbb2ff0bea51ef3549628f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 6 Apr 2022 11:18:56 +0200 Subject: [PATCH 114/188] New translations app.json (Russian) --- .../StringsConvertor/input/ru_RU/app.json | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Localization/StringsConvertor/input/ru_RU/app.json b/Localization/StringsConvertor/input/ru_RU/app.json index 0309c463..f211080e 100644 --- a/Localization/StringsConvertor/input/ru_RU/app.json +++ b/Localization/StringsConvertor/input/ru_RU/app.json @@ -46,7 +46,7 @@ }, "delete_post": { "title": "Вы уверены, что хотите удалить этот пост?", - "message": "Are you sure you want to delete this post?" + "message": "Вы уверены, что хотите удалить этот пост?" }, "clean_cache": { "title": "Очистка кэша", @@ -130,7 +130,7 @@ "show_user_profile": "Показать профиль пользователя", "content_warning": "Предупреждение о содержании", "media_content_warning": "Нажмите в любом месте, чтобы показать", - "tap_to_reveal": "Tap to reveal", + "tap_to_reveal": "Нажмите, чтобы показать", "poll": { "vote": "Проголосовать", "closed": "Завершён" @@ -142,11 +142,11 @@ "favorite": "Добавить в избранное", "unfavorite": "Убрать из избранного", "menu": "Меню", - "hide": "Hide", - "show_image": "Show image", - "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "hide": "Скрыть", + "show_image": "Показать изображение", + "show_gif": "Показать GIF", + "show_video_player": "Показать видеопроигрыватель", + "tap_then_hold_to_show_menu": "Нажмите и удерживайте, чтобы показать меню" }, "tag": { "url": "Ссылка", @@ -175,7 +175,7 @@ "unblock_user": "Разблокировать %s", "blocked": "В заблокированных", "mute": "Игнорировать", - "mute_user": "Добавить %s в игнорируемые", + "mute_user": "Игнорировать %s", "unmute": "Убрать из игнорируемых", "unmute_user": "Убрать %s из игнорируемых", "muted": "В игнорируемых", @@ -206,7 +206,7 @@ "scene": { "welcome": { "slogan": "Социальная сеть\nпод вашим контролем.", - "get_started": "Get Started", + "get_started": "Присоединиться", "log_in": "Вход" }, "server_picker": { @@ -321,7 +321,7 @@ "subtitle": "Мы только что отправили письмо на\n%s.\nНажмите на ссылку в нём, чтобы\nподтвердить свою учётную запись.", "button": { "open_email_app": "Открыть приложение почты", - "resend": "Resend" + "resend": "Отправить заново" }, "dont_receive_email": { "title": "Проверьте свой e-mail адрес", @@ -424,7 +424,7 @@ "segmented_control": { "posts": "Посты", "replies": "Ответы", - "posts_and_replies": "Posts and Replies", + "posts_and_replies": "Посты и ответы", "media": "Медиа", "about": "About" }, @@ -553,7 +553,7 @@ "disable_avatar_animation": "Отключить анимацию аватарок", "disable_emoji_animation": "Отключить анимацию эмодзи", "using_default_browser": "Использовать браузер по умолчанию для открытия ссылок", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "Открывать ссылки в Мастодоне" }, "boring_zone": { "title": "Зона скукотищи", @@ -575,7 +575,7 @@ } }, "report": { - "title_report": "Report", + "title_report": "Жалоба", "title": "Пожаловаться на %s", "step1": "Шаг 1 из 2", "step2": "Шаг 2 из 2", From 8902a7e06a780200631dbc8eb3076a52b3a8b702 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 6 Apr 2022 12:29:12 +0200 Subject: [PATCH 115/188] New translations app.json (Russian) --- Localization/StringsConvertor/input/ru_RU/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/ru_RU/app.json b/Localization/StringsConvertor/input/ru_RU/app.json index f211080e..97281b0b 100644 --- a/Localization/StringsConvertor/input/ru_RU/app.json +++ b/Localization/StringsConvertor/input/ru_RU/app.json @@ -600,7 +600,7 @@ "add_account": "Add Account" }, "wizard": { - "new_in_mastodon": "New in Mastodon", + "new_in_mastodon": "Новое в Мастодоне", "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", "accessibility_hint": "Double tap to dismiss this wizard" } From 2ecf92dbe5e9a0e770bc7d49a12314e91f229a24 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 7 Apr 2022 19:27:47 +0800 Subject: [PATCH 116/188] chore: update secondary label color --- .../Colors/Label/primary.colorset/Contents.json | 6 +++--- .../Colors/Label/secondary.colorset/Contents.json | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/primary.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/primary.colorset/Contents.json index a36ab82c..0c0c8af0 100644 --- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/primary.colorset/Contents.json +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/primary.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.216", - "green" : "0.173", - "red" : "0.157" + "blue" : "55", + "green" : "44", + "red" : "40" } }, "idiom" : "universal" diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json index cd123376..b23080b6 100644 --- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json @@ -4,10 +4,10 @@ "color" : { "color-space" : "srgb", "components" : { - "alpha" : "0.600", - "blue" : "67", - "green" : "60", - "red" : "60" + "alpha" : "1.000", + "blue" : "133", + "green" : "112", + "red" : "102" } }, "idiom" : "universal" From 4c1870f921be9ad4692dce98897f341f72862236 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 7 Apr 2022 19:28:06 +0800 Subject: [PATCH 117/188] chore: update body font size to 17pt --- MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index b938f2b9..30e05d86 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -141,11 +141,11 @@ public final class StatusView: UIView { return style }() metaText.textAttributes = [ - .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .regular)), + .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)), .foregroundColor: Asset.Colors.Label.primary.color, ] metaText.linkAttributes = [ - .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold)), + .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)), .foregroundColor: Asset.Colors.brandBlue.color, ] return metaText From 2a986ec1ce82efd5e68ad630bf4df89167d8a43a Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 7 Apr 2022 19:49:04 +0800 Subject: [PATCH 118/188] fix: media sensitive button logic issue --- .../View/Content/StatusView+ViewModel.swift | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift index f848b37e..b09fdb44 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift @@ -321,9 +321,6 @@ extension StatusView.ViewModel { statusView.setSpoilerOverlayViewHidden(isHidden: isContentReveal) - let image = isContentReveal ? UIImage(systemName: "eye.slash.fill") : UIImage(systemName: "eye.fill") - statusView.contentSensitiveeToggleButton.setImage(image, for: .normal) - self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): isContentReveal: \(isContentReveal)") } .store(in: &disposeBag) @@ -335,29 +332,22 @@ extension StatusView.ViewModel { } .store(in: &disposeBag) -// // visibility -// Publishers.CombineLatest( -// $visibility, -// $isMyself -// ) -// .sink { visibility, isMyself in -// switch visibility { -// case .public: -// break -// case .unlisted: -// statusView.statusVisibilityView.label.text = "Everyone can see this post but not display in the public timeline." -// statusView.setVisibilityDisplay() -// case .private: -// statusView.statusVisibilityView.label.text = isMyself ? "Only my followers can see this post." : "Only their followers can see this post." -// statusView.setVisibilityDisplay() -// case .direct: -// statusView.statusVisibilityView.label.text = "Only mentioned user can see this post." -// statusView.setVisibilityDisplay() -// case ._other: -// break -// } -// } -// .store(in: &disposeBag) + // There are 2 conditions: + // 1. The content may non-sensitive with sensitive media + // 2. The content and media both senstivie + Publishers.CombineLatest( + $isContentSensitiveToggled, + $isMediaSensitiveToggled + ) + .map { $0 || $1 } + .sink { isSensitiveToggled in + // The button indicator go-to state for button action direction + // eye: when media is hidden + // eye-slash: when media display + let image = isSensitiveToggled ? UIImage(systemName: "eye.slash.fill") : UIImage(systemName: "eye.fill") + statusView.contentSensitiveeToggleButton.setImage(image, for: .normal) + } + .store(in: &disposeBag) } private func bindMedia(statusView: StatusView) { From 33d68e8b6dd0344b88a1fbe3a82cfb369ddb4bdf Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 7 Apr 2022 20:04:06 +0800 Subject: [PATCH 119/188] fix: grouped style default corner radius applied to appearance setting issue. resolve #350 --- .../Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift b/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift index 3760fd8e..44b6b39c 100644 --- a/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift +++ b/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift @@ -85,6 +85,9 @@ class SettingsAppearanceTableViewCell: UITableViewCell { subview.removeFromSuperview() } } + + // remove grouped style table corner radius + layer.cornerRadius = 0 } } From 67aa1d670b54b25fd21ac7b7f20a63b08f613b54 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 11 Apr 2022 12:27:26 +0800 Subject: [PATCH 120/188] fix: non-ascii character in URL can not open issue. resolve #304 --- Mastodon/Diffiable/Search/SearchHistorySection.swift | 8 ++++---- Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift | 10 +++++++--- .../Sources/MastodonUI/View/Content/StatusView.swift | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Mastodon/Diffiable/Search/SearchHistorySection.swift b/Mastodon/Diffiable/Search/SearchHistorySection.swift index dba1dc18..557b49f2 100644 --- a/Mastodon/Diffiable/Search/SearchHistorySection.swift +++ b/Mastodon/Diffiable/Search/SearchHistorySection.swift @@ -69,10 +69,10 @@ extension SearchHistorySection { let trendHeaderRegister = UICollectionView.SupplementaryRegistration(elementKind: UICollectionView.elementKindSectionHeader) { [weak dataSource] supplementaryView, elementKind, indexPath in supplementaryView.delegate = configuration.searchHistorySectionHeaderCollectionReusableViewDelegate - guard let dataSource = dataSource else { return } - let sections = dataSource.snapshot().sectionIdentifiers - guard indexPath.section < sections.count else { return } - let section = sections[indexPath.section] + guard let _ = dataSource else { return } + // let sections = dataSource.snapshot().sectionIdentifiers + // guard indexPath.section < sections.count else { return } + // let section = sections[indexPath.section] } dataSource.supplementaryViewProvider = { (collectionView: UICollectionView, elementKind: String, indexPath: IndexPath) in diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift index bf54f70a..7e376ed0 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift @@ -38,11 +38,15 @@ extension DataSourceFacade { meta: Meta ) async { switch meta { + // note: + // some server mark the normal url as "u-url" class. highlighted content is a URL case .url(_, _, let url, _), .mention(_, let url, _) where url.lowercased().hasPrefix("http"): - // note: - // some server mark the normal url as "u-url" class. highlighted content is a URL - guard let url = URL(string: url) else { return } + // fix non-ascii character URL link can not open issue + guard let url = URL(string: url) ?? URL(string: url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? url) else { + assertionFailure() + return + } if let domain = provider.context.authenticationService.activeMastodonAuthenticationBox.value?.domain, url.host == domain, url.pathComponents.count >= 4, url.pathComponents[0] == "/", diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index 30e05d86..eb3a6935 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -757,7 +757,7 @@ extension StatusView: UITextViewDelegate { // MARK: - MetaTextViewDelegate extension StatusView: MetaTextViewDelegate { public func metaTextView(_ metaTextView: MetaTextView, didSelectMeta meta: Meta) { - logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): meta: \(String(describing: meta))") switch metaTextView { case contentMetaText.textView: delegate?.statusView(self, metaText: contentMetaText, didSelectMeta: meta) From 29d0ffdad0dd39aa8ec5f46e6239cc9260d43692 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 11 Apr 2022 23:29:56 +0200 Subject: [PATCH 121/188] New translations app.json (Chinese Simplified) --- .../StringsConvertor/input/zh_CN/app.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Localization/StringsConvertor/input/zh_CN/app.json b/Localization/StringsConvertor/input/zh_CN/app.json index e0b3e084..9fb1bddd 100644 --- a/Localization/StringsConvertor/input/zh_CN/app.json +++ b/Localization/StringsConvertor/input/zh_CN/app.json @@ -130,7 +130,7 @@ "show_user_profile": "查看用户个人资料", "content_warning": "内容警告", "media_content_warning": "点击任意位置显示", - "tap_to_reveal": "Tap to reveal", + "tap_to_reveal": "点击以显示", "poll": { "vote": "投票", "closed": "已关闭" @@ -143,10 +143,10 @@ "unfavorite": "取消喜欢", "menu": "菜单", "hide": "隐藏", - "show_image": "Show image", - "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_image": "显示图片", + "show_gif": "显示 GIF", + "show_video_player": "显示视频播放器", + "tap_then_hold_to_show_menu": "长按以显示菜单" }, "tag": { "url": "URL", @@ -447,10 +447,10 @@ } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", + "show_avatar_image": "显示头像", + "edit_avatar_image": "编辑头像", "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "double_tap_to_open_the_list": "双击打开列表" } }, "follower": { @@ -553,7 +553,7 @@ "disable_avatar_animation": "禁用动画头像", "disable_emoji_animation": "禁用动画表情", "using_default_browser": "使用默认浏览器打开链接", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "在 Mastodon 中打开链接" }, "boring_zone": { "title": "The Boring Zone", From 12f2b861ae5e664c9a81c47acd2961685f0b4668 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 11 Apr 2022 23:29:57 +0200 Subject: [PATCH 122/188] New translations Localizable.stringsdict (Chinese Simplified) --- .../StringsConvertor/input/zh_CN/Localizable.stringsdict | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict index 41890383..6c2661ee 100644 --- a/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/zh_CN/Localizable.stringsdict @@ -111,7 +111,7 @@ NSStringFormatValueTypeKey ld other - %ld replies + %ld 条回复 plural.count.vote From af619e198a77bbec5216bf0c742ebcb3ac5dceaa Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 12 Apr 2022 17:32:38 +0800 Subject: [PATCH 123/188] feat: add Discovery page with posts segment --- Localization/app.json | 8 + Mastodon.xcodeproj/project.pbxproj | 44 ++++ .../xcschemes/xcschememanagement.plist | 6 +- .../Discovery/DiscoveryViewController.swift | 94 ++++++++ .../Scene/Discovery/DiscoveryViewModel.swift | 72 ++++++ ...stsViewController+DataSourceProvider.swift | 34 +++ .../Posts/DiscoveryPostsViewController.swift | 118 ++++++++++ .../DiscoveryPostsViewModel+Diffable.swift | 63 ++++++ .../Posts/DiscoveryPostsViewModel+State.swift | 208 ++++++++++++++++++ .../Posts/DiscoveryPostsViewModel.swift | 59 +++++ .../Scene/Profile/ProfileViewController.swift | 1 + .../Timeline/UserTimelineViewController.swift | 2 +- .../Search/Search/SearchViewController.swift | 17 ++ .../Scene/Search/Search/SearchViewModel.swift | 2 +- .../Service/APIService/APIService+Trend.swift | 38 +++- .../MastodonSDK/API/Mastodon+API+Trends.swift | 74 ++++++- .../Response/Mastodon+Response+Content.swift | 10 + 17 files changed, 837 insertions(+), 13 deletions(-) create mode 100644 Mastodon/Scene/Discovery/DiscoveryViewController.swift create mode 100644 Mastodon/Scene/Discovery/DiscoveryViewModel.swift create mode 100644 Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift create mode 100644 Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift create mode 100644 Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift create mode 100644 Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift create mode 100644 Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift diff --git a/Localization/app.json b/Localization/app.json index f0dc0ebf..548c5ada 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -492,6 +492,14 @@ "clear": "Clear" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index cbcd948b..98da1374 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -550,6 +550,13 @@ DBD5B1F827BCFD9D00BD6B38 /* DataSourceProvider+TableViewControllerNavigateable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD5B1F727BCFD9D00BD6B38 /* DataSourceProvider+TableViewControllerNavigateable.swift */; }; DBD5B1FA27BD013700BD6B38 /* DataSourceProvider+StatusTableViewControllerNavigateable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD5B1F927BD013700BD6B38 /* DataSourceProvider+StatusTableViewControllerNavigateable.swift */; }; DBD9149025DF6D8D00903DFD /* APIService+Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */; }; + DBDFF1902805543100557A48 /* DiscoveryPostsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF18F2805543100557A48 /* DiscoveryPostsViewController.swift */; }; + DBDFF1932805554900557A48 /* DiscoveryPostsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF1922805554900557A48 /* DiscoveryPostsViewModel.swift */; }; + DBDFF1952805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF1942805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift */; }; + DBDFF197280556D900557A48 /* DiscoveryPostsViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF196280556D900557A48 /* DiscoveryPostsViewModel+State.swift */; }; + DBDFF19A28055A1400557A48 /* DiscoveryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF19928055A1400557A48 /* DiscoveryViewController.swift */; }; + DBDFF19C28055BD600557A48 /* DiscoveryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF19B28055BD600557A48 /* DiscoveryViewModel.swift */; }; + DBDFF19E2805703700557A48 /* DiscoveryPostsViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF19D2805703700557A48 /* DiscoveryPostsViewController+DataSourceProvider.swift */; }; DBE0821525CD382600FD6BBD /* MastodonRegisterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */; }; DBE0822425CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */; }; DBE3CA6827A39CAB00AFE27B /* AppShared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB68047F2637CD4C00430867 /* AppShared.framework */; }; @@ -1293,6 +1300,13 @@ DBD5B1F727BCFD9D00BD6B38 /* DataSourceProvider+TableViewControllerNavigateable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceProvider+TableViewControllerNavigateable.swift"; sourceTree = ""; }; DBD5B1F927BD013700BD6B38 /* DataSourceProvider+StatusTableViewControllerNavigateable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceProvider+StatusTableViewControllerNavigateable.swift"; sourceTree = ""; }; DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Onboarding.swift"; sourceTree = ""; }; + DBDFF18F2805543100557A48 /* DiscoveryPostsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryPostsViewController.swift; sourceTree = ""; }; + DBDFF1922805554900557A48 /* DiscoveryPostsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryPostsViewModel.swift; sourceTree = ""; }; + DBDFF1942805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryPostsViewModel+Diffable.swift"; sourceTree = ""; }; + DBDFF196280556D900557A48 /* DiscoveryPostsViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryPostsViewModel+State.swift"; sourceTree = ""; }; + DBDFF19928055A1400557A48 /* DiscoveryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryViewController.swift; sourceTree = ""; }; + DBDFF19B28055BD600557A48 /* DiscoveryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryViewModel.swift; sourceTree = ""; }; + DBDFF19D2805703700557A48 /* DiscoveryPostsViewController+DataSourceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryPostsViewController+DataSourceProvider.swift"; sourceTree = ""; }; DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterViewController.swift; sourceTree = ""; }; DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterViewModel.swift; sourceTree = ""; }; DBE3CDBA261C427900430CC6 /* TimelineHeaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineHeaderTableViewCell.swift; sourceTree = ""; }; @@ -2682,6 +2696,7 @@ 2DAC9E36262FC20B0062E1A6 /* SuggestionAccount */, DB9D6C0825E4F5A60051B173 /* Profile */, DB9D6BEE25E4F5370051B173 /* Search */, + DBDFF1912805544800557A48 /* Discovery */, 5B90C455262599800002E742 /* Settings */, ); path = Scene; @@ -3068,6 +3083,28 @@ path = FetchedResultsController; sourceTree = ""; }; + DBDFF1912805544800557A48 /* Discovery */ = { + isa = PBXGroup; + children = ( + DBDFF19828055A0900557A48 /* Posts */, + DBDFF19928055A1400557A48 /* DiscoveryViewController.swift */, + DBDFF19B28055BD600557A48 /* DiscoveryViewModel.swift */, + ); + path = Discovery; + sourceTree = ""; + }; + DBDFF19828055A0900557A48 /* Posts */ = { + isa = PBXGroup; + children = ( + DBDFF18F2805543100557A48 /* DiscoveryPostsViewController.swift */, + DBDFF19D2805703700557A48 /* DiscoveryPostsViewController+DataSourceProvider.swift */, + DBDFF1922805554900557A48 /* DiscoveryPostsViewModel.swift */, + DBDFF1942805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift */, + DBDFF196280556D900557A48 /* DiscoveryPostsViewModel+State.swift */, + ); + path = Posts; + sourceTree = ""; + }; DBE0821A25CD382900FD6BBD /* Register */ = { isa = PBXGroup; children = ( @@ -3797,6 +3834,7 @@ buildActionMask = 2147483647; files = ( DBB525212611EBD6002F1F29 /* ProfilePagingViewController.swift in Sources */, + DBDFF19E2805703700557A48 /* DiscoveryPostsViewController+DataSourceProvider.swift in Sources */, DB6180EB26391C140018D199 /* MediaPreviewTransitionItem.swift in Sources */, DB63F74727990B0600455B82 /* DataSourceFacade+Hashtag.swift in Sources */, DB98337125C9443200AD9700 /* APIService+Authentication.swift in Sources */, @@ -3858,6 +3896,7 @@ DB697DD6278F4C29004EF2F7 /* DataSourceProvider.swift in Sources */, DB0FCB8E2796C0B7006C02E2 /* TrendCollectionViewCell.swift in Sources */, 0F1E2D0B2615C39400C38565 /* DoubleTitleLabelNavigationBarTitleView.swift in Sources */, + DBDFF1902805543100557A48 /* DiscoveryPostsViewController.swift in Sources */, DB697DD9278F4CED004EF2F7 /* HomeTimelineViewController+DataSourceProvider.swift in Sources */, DB9A488A26034D40008B817C /* ComposeViewModel+PublishState.swift in Sources */, DB45FAD725CA6C76005A8AC7 /* UIBarButtonItem.swift in Sources */, @@ -3878,7 +3917,9 @@ DB297B1B2679FAE200704C90 /* PlaceholderImageCacheService.swift in Sources */, DB0FCB8C2796BF8D006C02E2 /* SearchViewModel+Diffable.swift in Sources */, 2D8FCA082637EABB00137F46 /* APIService+FollowRequest.swift in Sources */, + DBDFF1952805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift in Sources */, DB03A795272A981400EE37C5 /* ContentSplitViewController.swift in Sources */, + DBDFF19C28055BD600557A48 /* DiscoveryViewModel.swift in Sources */, DBBC24DE26A54BCB00398BB9 /* MastodonMetricFormatter.swift in Sources */, DB06180A2785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift in Sources */, DBB45B6227B51112002DC5A7 /* SuggestionAccountViewModel+Diffable.swift in Sources */, @@ -4012,6 +4053,7 @@ DB1D843026566512000346B3 /* KeyboardPreference.swift in Sources */, DB852D1926FAEB6B00FC9D81 /* SidebarViewController.swift in Sources */, 2D206B9225F60EA700143C56 /* UIControl.swift in Sources */, + DBDFF1932805554900557A48 /* DiscoveryPostsViewModel.swift in Sources */, 2D9DB96B263A91D1007C1D71 /* APIService+DomainBlock.swift in Sources */, DBBF1DC92652538500E5B703 /* AutoCompleteSection.swift in Sources */, DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */, @@ -4069,6 +4111,7 @@ 2D5981A125E4A593000FB903 /* MastodonConfirmEmailViewModel.swift in Sources */, DB6B74F6272FBCDB00C70B6E /* FollowerListViewModel+State.swift in Sources */, DB87D4452609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift in Sources */, + DBDFF197280556D900557A48 /* DiscoveryPostsViewModel+State.swift in Sources */, DB336F2C278D6FC30031E64B /* Persistence+Status.swift in Sources */, DB336F2A278D6F2B0031E64B /* MastodonField.swift in Sources */, DB0FCB7A279576A2006C02E2 /* DataSourceFacade+Thread.swift in Sources */, @@ -4246,6 +4289,7 @@ DB6F5E38264E994A009108F4 /* AutoCompleteTopChevronView.swift in Sources */, DB6746F0278F463B008A6B94 /* AutoGenerateProtocolDelegate.swift in Sources */, DBB525412611ED54002F1F29 /* ProfileHeaderViewController.swift in Sources */, + DBDFF19A28055A1400557A48 /* DiscoveryViewController.swift in Sources */, DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */, DB63F756279949BD00455B82 /* Persistence+SearchHistory.swift in Sources */, 2D4AD8A226316CD200613EFC /* SelectedAccountSection.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index ad09868c..92edf05d 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 24 + 23 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 22 + 24 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 23 + 22 SuppressBuildableAutocreation diff --git a/Mastodon/Scene/Discovery/DiscoveryViewController.swift b/Mastodon/Scene/Discovery/DiscoveryViewController.swift new file mode 100644 index 00000000..4f909d6c --- /dev/null +++ b/Mastodon/Scene/Discovery/DiscoveryViewController.swift @@ -0,0 +1,94 @@ +// +// DiscoveryViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import os.log +import UIKit +import Combine +import Tabman +import MastodonAsset + +public class DiscoveryViewController: TabmanViewController, NeedsDependency { + + public static let containerViewMarginForRegularHorizontalSizeClass: CGFloat = 64 + public static let containerViewMarginForCompactHorizontalSizeClass: CGFloat = 16 + + var disposeBag = Set() + + let logger = Logger(subsystem: "DiscoveryViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + private(set) lazy var viewModel = DiscoveryViewModel( + context: context, + coordinator: coordinator + ) + + let buttonBar: TMBar.ButtonBar = { + let buttonBar = TMBar.ButtonBar() + buttonBar.indicator.backgroundColor = Asset.Colors.Label.primary.color + buttonBar.layout.contentInset = .zero + return buttonBar + }() + +} + +extension DiscoveryViewController { + + public override func viewDidLoad() { + super.viewDidLoad() + + setupAppearance(theme: ThemeService.shared.currentTheme.value) + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.setupAppearance(theme: theme) + } + .store(in: &disposeBag) + + dataSource = viewModel + addBar( + buttonBar, + dataSource: viewModel, + at: .top + ) + updateBarButtonInsets() + } + + public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + updateBarButtonInsets() + } + +} + +extension DiscoveryViewController { + + private func setupAppearance(theme: Theme) { + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + buttonBar.backgroundView.style = .flat(color: theme.systemBackgroundColor) + } + + private func updateBarButtonInsets() { + let margin: CGFloat = { + switch traitCollection.userInterfaceIdiom { + case .phone: + return DiscoveryViewController.containerViewMarginForCompactHorizontalSizeClass + default: + return traitCollection.horizontalSizeClass == .regular ? + DiscoveryViewController.containerViewMarginForRegularHorizontalSizeClass : + DiscoveryViewController.containerViewMarginForCompactHorizontalSizeClass + } + }() + + buttonBar.layout.contentInset.left = margin + buttonBar.layout.contentInset.right = margin + } + +} diff --git a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift new file mode 100644 index 00000000..137b8682 --- /dev/null +++ b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift @@ -0,0 +1,72 @@ +// +// DiscoveryViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import UIKit +import Tabman +import Pageboy + +final class DiscoveryViewModel { + + // input + let context: AppContext + let discoveryViewController: DiscoveryPostsViewController + + // output + let barItems: [TMBarItemable] = { + let items = [ + TMBarItem(title: "Posts"), + TMBarItem(title: "Hashtags"), + TMBarItem(title: "News"), + TMBarItem(title: "For You"), + ] + return items + }() + + var viewControllers: [ScrollViewContainer] { + return [ + discoveryViewController, + ] + } + + init(context: AppContext, coordinator: SceneCoordinator) { + self.context = context + discoveryViewController = { + let viewController = DiscoveryPostsViewController() + viewController.context = context + viewController.coordinator = coordinator + viewController.viewModel = DiscoveryPostsViewModel(context: context) + return viewController + }() + // end init + } + +} + + +// MARK: - PageboyViewControllerDataSource +extension DiscoveryViewModel: PageboyViewControllerDataSource { + + func numberOfViewControllers(in pageboyViewController: PageboyViewController) -> Int { + return viewControllers.count + } + + func viewController(for pageboyViewController: PageboyViewController, at index: PageboyViewController.PageIndex) -> UIViewController? { + return viewControllers[index] + } + + func defaultPage(for pageboyViewController: PageboyViewController) -> PageboyViewController.Page? { + return .first + } + +} + +// MARK: - TMBarDataSource +extension DiscoveryViewModel: TMBarDataSource { + func barItem(for bar: TMBar, at index: Int) -> TMBarItemable { + return barItems[index] + } +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift new file mode 100644 index 00000000..c3495b24 --- /dev/null +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift @@ -0,0 +1,34 @@ +// +// DiscoveryPostsViewController+DataSourceProvider.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import UIKit + +extension DiscoveryPostsViewController: DataSourceProvider { + func item(from source: DataSourceItem.Source) async -> DataSourceItem? { + var _indexPath = source.indexPath + if _indexPath == nil, let cell = source.tableViewCell { + _indexPath = await self.indexPath(for: cell) + } + guard let indexPath = _indexPath else { return nil } + + guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { + return nil + } + + switch item { + case .status(let record): + return .status(record: record) + default: + return nil + } + } + + @MainActor + private func indexPath(for cell: UITableViewCell) async -> IndexPath? { + return tableView.indexPath(for: cell) + } +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift new file mode 100644 index 00000000..3e813dbd --- /dev/null +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift @@ -0,0 +1,118 @@ +// +// DiscoveryPostsViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import os.log +import UIKit +import Combine + +final class DiscoveryPostsViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + + let logger = Logger(subsystem: "TrendPostsViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var viewModel: DiscoveryPostsViewModel! + + let mediaPreviewTransitionController = MediaPreviewTransitionController() + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 100 + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + return tableView + }() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension DiscoveryPostsViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.view.backgroundColor = theme.secondarySystemBackgroundColor + } + .store(in: &disposeBag) + + tableView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(tableView) + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + tableView.delegate = self + viewModel.setupDiffableDataSource( + tableView: tableView, + statusTableViewCellDelegate: self + ) + + // setup batch fetch + viewModel.listBatchFetchViewModel.setup(scrollView: tableView) + viewModel.listBatchFetchViewModel.shouldFetch + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + guard self.view.window != nil else { return } + self.viewModel.stateMachine.enter(DiscoveryPostsViewModel.State.Loading.self) + } + .store(in: &disposeBag) + } + +} + +// MARK: - UITableViewDelegate +extension DiscoveryPostsViewController: UITableViewDelegate, AutoGenerateTableViewDelegate { + // sourcery:inline:DiscoveryPostsViewController.AutoGenerateTableViewDelegate + + // Generated using Sourcery + // DO NOT EDIT + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + aspectTableView(tableView, didSelectRowAt: indexPath) + } + + func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { + return aspectTableView(tableView, contextMenuConfigurationForRowAt: indexPath, point: point) + } + + func tableView(_ tableView: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { + return aspectTableView(tableView, previewForHighlightingContextMenuWithConfiguration: configuration) + } + + func tableView(_ tableView: UITableView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { + return aspectTableView(tableView, previewForDismissingContextMenuWithConfiguration: configuration) + } + + func tableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) { + aspectTableView(tableView, willPerformPreviewActionForMenuWith: configuration, animator: animator) + } + // sourcery:end +} + +// MARK: - StatusTableViewCellDelegate +extension DiscoveryPostsViewController: StatusTableViewCellDelegate { } + +// MARK: ScrollViewContainer +extension DiscoveryPostsViewController: ScrollViewContainer { + var scrollView: UIScrollView? { + tableView + } +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift new file mode 100644 index 00000000..3abb4a21 --- /dev/null +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift @@ -0,0 +1,63 @@ +// +// DiscoveryPostsViewModel+Diffable.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import UIKit +import Combine + +extension DiscoveryPostsViewModel { + + func setupDiffableDataSource( + tableView: UITableView, + statusTableViewCellDelegate: StatusTableViewCellDelegate + ) { + diffableDataSource = StatusSection.diffableDataSource( + tableView: tableView, + context: context, + configuration: StatusSection.Configuration( + statusTableViewCellDelegate: statusTableViewCellDelegate, + timelineMiddleLoaderTableViewCellDelegate: nil, + filterContext: .none, + activeFilters: nil + ) + ) + + stateMachine.enter(State.Reloading.self) + + statusFetchedResultsController.$records + .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main) + .sink { [weak self] records in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + + let items = records.map { StatusItem.status(record: $0) } + snapshot.appendItems(items, toSection: .main) + + if let currentState = self.stateMachine.currentState { + switch currentState { + case is State.Initial, + is State.Reloading, + is State.Loading, + is State.Idle, + is State.Fail: + snapshot.appendItems([.bottomLoader], toSection: .main) + case is State.NoMore: + break + default: + assertionFailure() + break + } + } + + diffableDataSource.applySnapshot(snapshot, animated: false) + } + .store(in: &disposeBag) + } + +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift new file mode 100644 index 00000000..0a217868 --- /dev/null +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift @@ -0,0 +1,208 @@ +// +// DiscoveryPostsViewModel+State.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import os.log +import Foundation +import GameplayKit +import MastodonSDK + +extension DiscoveryPostsViewModel { + class State: GKState, NamingState { + + let logger = Logger(subsystem: "TrendPostsViewModel.State", category: "StateMachine") + + let id = UUID() + + var name: String { + String(describing: Self.self) + } + + weak var viewModel: DiscoveryPostsViewModel? + + init(viewModel: DiscoveryPostsViewModel) { + self.viewModel = viewModel + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + let previousState = previousState as? DiscoveryPostsViewModel.State + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(self.id.uuidString)] enter \(self.name), previous: \(previousState?.name ?? "")") + } + + @MainActor + func enter(state: State.Type) { + stateMachine?.enter(state) + } + + deinit { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(self.id.uuidString)] \(self.name)") + } + } +} + +extension DiscoveryPostsViewModel.State { + class Initial: DiscoveryPostsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + } + + class Reloading: DiscoveryPostsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + // reset + viewModel.statusFetchedResultsController.statusIDs.value = [] + + stateMachine.enter(Loading.self) + } + } + + class Fail: DiscoveryPostsViewModel.State { + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let _ = viewModel, let stateMachine = stateMachine else { return } + + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading 3s later…", ((#file as NSString).lastPathComponent), #line, #function) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading", ((#file as NSString).lastPathComponent), #line, #function) + stateMachine.enter(Loading.self) + } + } + } + + class Idle: DiscoveryPostsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type, is Loading.Type: + return true + default: + return false + } + } + } + + class Loading: DiscoveryPostsViewModel.State { + + var offset: Int? + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Fail.Type: + return true + case is Idle.Type: + return true + case is NoMore.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + + switch previousState { + case is Reloading: + offset = nil + default: + break + } + + guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else { + stateMachine.enter(Fail.self) + return + } + + let offset = self.offset + + Task { + do { + let response = try await viewModel.context.apiService.trendStatuses( + domain: authenticationBox.domain, + query: Mastodon.API.Trends.StatusQuery( + offset: offset, + limit: nil + ) + ) + let newOffset: Int? = { + guard let offset = response.link?.offset else { return nil } + return self.offset.flatMap { max($0, offset) } ?? offset + }() + + let hasMore: Bool = { + guard let newOffset = newOffset else { return false } + return newOffset != self.offset // not the same one + }() + + self.offset = newOffset + + var hasNewStatusesAppend = false + var statusIDs = viewModel.statusFetchedResultsController.statusIDs.value + for status in response.value { + guard !statusIDs.contains(status.id) else { continue } + statusIDs.append(status.id) + hasNewStatusesAppend = true + } + + if hasNewStatusesAppend, hasMore { + await enter(state: Idle.self) + } else { + await enter(state: NoMore.self) + } + viewModel.statusFetchedResultsController.statusIDs.value = statusIDs + + } catch { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch user timeline fail: \(error.localizedDescription)") + await enter(state: Fail.self) + } + } // end Task + } // end func + } + + class NoMore: DiscoveryPostsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + } + } +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift new file mode 100644 index 00000000..100a2a34 --- /dev/null +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift @@ -0,0 +1,59 @@ +// +// DiscoveryPostsViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import os.log +import UIKit +import Combine +import GameplayKit +import CoreData +import CoreDataStack +import MastodonSDK + +final class DiscoveryPostsViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + let statusFetchedResultsController: StatusFetchedResultsController + let listBatchFetchViewModel = ListBatchFetchViewModel() + + // output + var diffableDataSource: UITableViewDiffableDataSource? + private(set) lazy var stateMachine: GKStateMachine = { + let stateMachine = GKStateMachine(states: [ + State.Initial(viewModel: self), + State.Reloading(viewModel: self), + State.Fail(viewModel: self), + State.Idle(viewModel: self), + State.Loading(viewModel: self), + State.NoMore(viewModel: self), + ]) + stateMachine.enter(State.Initial.self) + return stateMachine + }() + + init(context: AppContext) { + self.context = context + self.statusFetchedResultsController = StatusFetchedResultsController( + managedObjectContext: context.managedObjectContext, + domain: nil, + additionalTweetPredicate: nil + ) + // end init + + context.authenticationService.activeMastodonAuthentication + .map { $0?.domain } + .assign(to: \.value, on: statusFetchedResultsController.domain) + .store(in: &disposeBag) + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index a890505e..55a952b0 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -402,6 +402,7 @@ extension ProfileViewController { } extension ProfileViewController { + private func updateBarButtonInsets() { let margin: CGFloat = { switch traitCollection.userInterfaceIdiom { diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift index 12925ca4..d9e52a8c 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift @@ -36,7 +36,7 @@ final class UserTimelineViewController: UIViewController, NeedsDependency, Media let cellFrameCache = NSCache() deinit { - os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } } diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift index d1bed948..6f4d2200 100644 --- a/Mastodon/Scene/Search/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/Search/SearchViewController.swift @@ -48,6 +48,13 @@ final class SearchViewController: UIViewController, NeedsDependency { let searchBarTapPublisher = PassthroughSubject() + private(set) lazy var trendViewController: DiscoveryViewController = { + let viewController = DiscoveryViewController() + viewController.context = context + viewController.coordinator = coordinator + return viewController + }() + deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } @@ -84,6 +91,16 @@ extension SearchViewController { viewModel.setupDiffableDataSource( collectionView: collectionView ) + + addChild(trendViewController) + trendViewController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(trendViewController.view) + NSLayoutConstraint.activate([ + trendViewController.view.topAnchor.constraint(equalTo: view.topAnchor), + trendViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + trendViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + trendViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) } override func viewDidAppear(_ animated: Bool) { diff --git a/Mastodon/Scene/Search/Search/SearchViewModel.swift b/Mastodon/Scene/Search/Search/SearchViewModel.swift index 2776713d..84e09725 100644 --- a/Mastodon/Scene/Search/Search/SearchViewModel.swift +++ b/Mastodon/Scene/Search/Search/SearchViewModel.swift @@ -38,7 +38,7 @@ final class SearchViewModel: NSObject { } .throttle(for: 3, scheduler: DispatchQueue.main, latest: true) .asyncMap { authenticationBox in - try await context.apiService.trends(domain: authenticationBox.domain, query: nil) + try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil) } .retry(3) .map { response in Result, Error> { response } } diff --git a/Mastodon/Service/APIService/APIService+Trend.swift b/Mastodon/Service/APIService/APIService+Trend.swift index 0ce2a86a..34edae09 100644 --- a/Mastodon/Service/APIService/APIService+Trend.swift +++ b/Mastodon/Service/APIService/APIService+Trend.swift @@ -9,11 +9,12 @@ import Foundation import MastodonSDK extension APIService { - func trends( + + func trendHashtags( domain: String, - query: Mastodon.API.Trends.Query? + query: Mastodon.API.Trends.HashtagQuery? ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Tag]> { - let response = try await Mastodon.API.Trends.get( + let response = try await Mastodon.API.Trends.hashtags( session: session, domain: domain, query: query @@ -21,4 +22,35 @@ extension APIService { return response } + + func trendStatuses( + domain: String, + query: Mastodon.API.Trends.StatusQuery + ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Status]> { + let response = try await Mastodon.API.Trends.statuses( + session: session, + domain: domain, + query: query + ).singleOutput() + + let managedObjectContext = backgroundManagedObjectContext + try await managedObjectContext.performChanges { + for entity in response.value { + _ = Persistence.Status.createOrMerge( + in: managedObjectContext, + context: Persistence.Status.PersistContext( + domain: domain, + entity: entity, + me: nil, + statusCache: nil, + userCache: nil, + networkDate: response.networkDate + ) + ) + } // end for … in + } + + return response + } + } diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift index 385e3d75..25e130e3 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift @@ -9,6 +9,7 @@ import Combine import Foundation extension Mastodon.API.Trends { + static func trendsURL(domain: String) -> URL { Mastodon.API.endpointURL(domain: domain).appendingPathComponent("trends") } @@ -27,10 +28,10 @@ extension Mastodon.API.Trends { /// - query: query /// - Returns: `AnyPublisher` contains `Hashtags` nested in the response - public static func get( + public static func hashtags( session: URLSession, domain: String, - query: Mastodon.API.Trends.Query? + query: Mastodon.API.Trends.HashtagQuery? ) -> AnyPublisher, Error> { let request = Mastodon.API.get( url: trendsURL(domain: domain), @@ -44,10 +45,8 @@ extension Mastodon.API.Trends { } .eraseToAnyPublisher() } -} -extension Mastodon.API.Trends { - public struct Query: Codable, GetQuery { + public struct HashtagQuery: Codable, GetQuery { public init(limit: Int?) { self.limit = limit } @@ -61,4 +60,69 @@ extension Mastodon.API.Trends { return items } } + +} + +extension Mastodon.API.Trends { + + static func trendStatusesURL(domain: String) -> URL { + Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("trends") + .appendingPathComponent("statuses") + } + + /// Trending tags + /// + /// Tags that are being used more frequently within the past week. + /// + /// Version history: + /// 3.?.? + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/instance/trends/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - query: query + /// - Returns: `AnyPublisher` contains `Hashtags` nested in the response + + public static func statuses( + session: URLSession, + domain: String, + query: Mastodon.API.Trends.StatusQuery? + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: trendStatusesURL(domain: domain), + query: query, + authorization: nil + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: [Mastodon.Entity.Status].self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + + public struct StatusQuery: Codable, GetQuery { + + public let offset: Int? + public let limit: Int? // Maximum number of results to return. Defaults to 10. + + public init( + offset: Int?, + limit: Int? + ) { + self.offset = offset + self.limit = limit + } + + var queryItems: [URLQueryItem]? { + var items: [URLQueryItem] = [] + offset.flatMap { items.append(URLQueryItem(name: "offset", value: String($0))) } + limit.flatMap { items.append(URLQueryItem(name: "limit", value: String($0))) } + guard !items.isEmpty else { return nil } + return items + } + } + } diff --git a/MastodonSDK/Sources/MastodonSDK/Response/Mastodon+Response+Content.swift b/MastodonSDK/Sources/MastodonSDK/Response/Mastodon+Response+Content.swift index db42169d..6cf95752 100644 --- a/MastodonSDK/Sources/MastodonSDK/Response/Mastodon+Response+Content.swift +++ b/MastodonSDK/Sources/MastodonSDK/Response/Mastodon+Response+Content.swift @@ -106,6 +106,7 @@ extension Mastodon.Response { public struct Link { public let maxID: Mastodon.Entity.Status.ID? public let minID: Mastodon.Entity.Status.ID? + public let offset: Int? init(link: String) { self.maxID = { @@ -125,6 +126,15 @@ extension Mastodon.Response { let id = link[range] return String(id) }() + + self.offset = { + guard let regex = try? NSRegularExpression(pattern: "offset=([[:digit:]]+)", options: []) else { return nil } + let results = regex.matches(in: link, options: [], range: NSRange(link.startIndex.. Date: Wed, 13 Apr 2022 20:43:16 +0800 Subject: [PATCH 124/188] feat: add hashtag and news list for Discovery scene --- Mastodon.xcodeproj/project.pbxproj | 120 ++++++---- .../xcshareddata/xcschemes/Mastodon.xcscheme | 8 + .../xcschemes/xcschememanagement.plist | 4 +- .../Diffiable/Discovery/DiscoveryItem.swift | 15 ++ .../Discovery/DiscoverySection.swift | 52 +++++ Mastodon/Diffiable/Search/SearchSection.swift | 19 -- .../MastodonSDK/Mastodon+Entity+Tag.swift | 11 - .../MastodonUI/ThemeService.swift} | 6 +- Mastodon/Extension/UIView.swift | 70 ------ Mastodon/Preference/ThemePreference.swift | 14 -- ...seStatusPollOptionCollectionViewCell.swift | 1 + .../Discovery/DiscoveryViewController.swift | 1 + .../Scene/Discovery/DiscoveryViewModel.swift | 30 ++- .../DiscoveryHashtagsViewController.swift | 113 ++++++++++ .../DiscoveryHashtagsViewModel+Diffable.swift | 42 ++++ .../Hashtags/DiscoveryHashtagsViewModel.swift | 63 ++++++ .../News/DiscoveryNewsViewController.swift | 133 +++++++++++ .../DiscoveryNewsViewModel+Diffable.swift | 60 +++++ .../News/DiscoveryNewsViewModel+State.swift | 209 ++++++++++++++++++ .../News/DiscoveryNewsViewModel.swift | 51 +++++ .../Posts/DiscoveryPostsViewController.swift | 30 +++ .../DiscoveryPostsViewModel+Diffable.swift | 8 +- .../Posts/DiscoveryPostsViewModel+State.swift | 8 +- .../Posts/DiscoveryPostsViewModel.swift | 2 + .../HomeTimelineViewController.swift | 3 +- .../Root/MainTab/MainTabBarController.swift | 1 + .../Root/Sidebar/SidebarViewController.swift | 1 + .../Search/Cell/TrendCollectionViewCell.swift | 79 +------ .../View/SearchHistoryTableHeaderView.swift | 1 + .../Content/ContentWarningOverlayView.swift | 1 + .../Content/MediaView+Configuration.swift | 2 +- .../Share/View/Content/ThreadMetaView.swift | 1 + .../Service/APIService/APIService+Trend.swift | 13 ++ Mastodon/Service/SettingService.swift | 15 +- .../Preference/Preference+Theme.swift | 26 +++ .../Sources/MastodonExtension/UIView.swift | 34 +++ .../Sources/MastodonExtension/UInt64.swift | 12 + .../MastodonSDK/API/Mastodon+API+Trends.swift | 50 ++++- .../Entity/Mastodon+Entity+Link.swift | 54 +++++ .../Entity/Mastodon+Entity+Tag.swift | 1 + .../MastodonSDK/Mastodon+Entity+Link.swift | 21 ++ .../MastodonSDK/Mastodon+Entity+Tag.swift | 21 ++ .../Sources/MastodonUI/Extension/UIView.swift | 34 +++ .../Service/ThemeService/MastodonTheme.swift | 1 + .../Service/ThemeService/SystemTheme.swift | 1 + .../Service/ThemeService/Theme.swift | 15 +- .../Service/ThemeService/ThemeService.swift | 16 +- .../MastodonUI/Vendor}/CurveAlgorithm.swift | 0 .../View/Content/NewsView+Configuration.swift | 43 ++++ .../MastodonUI/View/Content/NewsView.swift | 102 +++++++++ .../Content/TrendView+Configuration.swift | 35 +++ .../MastodonUI/View/Content/TrendView.swift | 100 +++++++++ .../View/Control}/LineChartView.swift | 20 +- .../TableViewCell/NewsTableViewCell.swift | 56 +++++ .../TableViewCell/TrendTableViewCell.swift | 86 +++++++ .../Scene/ShareViewController.swift | 1 + .../Scene/ShareViewModel.swift | 1 + .../Scene/View/ComposeToolbarView.swift | 1 + 58 files changed, 1619 insertions(+), 299 deletions(-) create mode 100644 Mastodon/Diffiable/Discovery/DiscoveryItem.swift create mode 100644 Mastodon/Diffiable/Discovery/DiscoverySection.swift rename Mastodon/{Service/ThemeService/ThemeService+Appearance.swift => Extension/MastodonUI/ThemeService.swift} (97%) delete mode 100644 Mastodon/Extension/UIView.swift create mode 100644 Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift create mode 100644 Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift create mode 100644 Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift create mode 100644 Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift create mode 100644 Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift create mode 100644 Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift create mode 100644 Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift create mode 100644 MastodonSDK/Sources/MastodonCommon/Preference/Preference+Theme.swift create mode 100644 MastodonSDK/Sources/MastodonExtension/UInt64.swift create mode 100644 MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Link.swift create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Link.swift create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Tag.swift create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/UIView.swift rename {Mastodon => MastodonSDK/Sources/MastodonUI}/Service/ThemeService/MastodonTheme.swift (98%) rename {Mastodon => MastodonSDK/Sources/MastodonUI}/Service/ThemeService/SystemTheme.swift (98%) rename {Mastodon => MastodonSDK/Sources/MastodonUI}/Service/ThemeService/Theme.swift (82%) rename {Mastodon => MastodonSDK/Sources/MastodonUI}/Service/ThemeService/ThemeService.swift (57%) rename {Mastodon/Vender => MastodonSDK/Sources/MastodonUI/Vendor}/CurveAlgorithm.swift (100%) create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/TrendView.swift rename {Mastodon/Scene/Search/Search/View => MastodonSDK/Sources/MastodonUI/View/Control}/LineChartView.swift (85%) create mode 100644 MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/TableViewCell/TrendTableViewCell.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 98da1374..73332bab 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -31,7 +31,6 @@ 2D206B9225F60EA700143C56 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D206B9125F60EA700143C56 /* UIControl.swift */; }; 2D24E1232626ED9D00A59D4F /* UIView+Gesture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D24E1222626ED9D00A59D4F /* UIView+Gesture.swift */; }; 2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */; }; - 2D32EABA25CB9B0500C9ED86 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D32EAB925CB9B0500C9ED86 /* UIView.swift */; }; 2D34D9D126148D9E0081BFC0 /* APIService+Recommend.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D34D9D026148D9E0081BFC0 /* APIService+Recommend.swift */; }; 2D34D9DB261494120081BFC0 /* APIService+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D34D9DA261494120081BFC0 /* APIService+Search.swift */; }; 2D35237A26256D920031AF25 /* NotificationSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D35237926256D920031AF25 /* NotificationSection.swift */; }; @@ -223,6 +222,16 @@ DB3667A6268AE2620027D07F /* ComposeStatusPollSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A5268AE2620027D07F /* ComposeStatusPollSection.swift */; }; DB3667A8268AE2900027D07F /* ComposeStatusPollItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A7268AE2900027D07F /* ComposeStatusPollItem.swift */; }; DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3D0FF225BAA61700EAA174 /* AlamofireImage */; }; + DB3E6FDD2806A40F00B035AE /* DiscoveryHashtagsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FDC2806A40F00B035AE /* DiscoveryHashtagsViewController.swift */; }; + DB3E6FE02806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FDF2806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift */; }; + DB3E6FE22806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FE12806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift */; }; + DB3E6FE42806A5B800B035AE /* DiscoverySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FE32806A5B800B035AE /* DiscoverySection.swift */; }; + DB3E6FE72806A7A200B035AE /* DiscoveryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FE62806A7A200B035AE /* DiscoveryItem.swift */; }; + DB3E6FE92806BD2200B035AE /* ThemeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FE82806BD2200B035AE /* ThemeService.swift */; }; + DB3E6FEC2806D7F100B035AE /* DiscoveryNewsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FEB2806D7F100B035AE /* DiscoveryNewsViewController.swift */; }; + DB3E6FEF2806D82600B035AE /* DiscoveryNewsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FEE2806D82600B035AE /* DiscoveryNewsViewModel.swift */; }; + DB3E6FF12806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF02806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift */; }; + DB3E6FF32806D97400B035AE /* DiscoveryNewsViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF22806D97400B035AE /* DiscoveryNewsViewModel+State.swift */; }; DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD525BAA00100D1B89D /* AppDelegate.swift */; }; DB427DD825BAA00100D1B89D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD725BAA00100D1B89D /* SceneDelegate.swift */; }; DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DB427DDB25BAA00100D1B89D /* Main.storyboard */; }; @@ -376,8 +385,6 @@ DB6D9F9726367249008423CD /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D9F9626367249008423CD /* SettingsViewController.swift */; }; DB6F5E35264E78E7009108F4 /* AutoCompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6F5E34264E78E7009108F4 /* AutoCompleteViewController.swift */; }; DB6F5E38264E994A009108F4 /* AutoCompleteTopChevronView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6F5E37264E994A009108F4 /* AutoCompleteTopChevronView.swift */; }; - DB71C7CB271D5A0300BE3819 /* LineChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71C7CA271D5A0300BE3819 /* LineChartView.swift */; }; - DB71C7CD271D7F4300BE3819 /* CurveAlgorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */; }; DB71FD5225F8CCAA00512AE1 /* APIService+Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD5125F8CCAA00512AE1 /* APIService+Status.swift */; }; DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */; }; DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */; }; @@ -508,16 +515,7 @@ DBBC24AA26A5301B00398BB9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24A926A5301B00398BB9 /* MastodonSDK */; }; DBBC24AC26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24AB26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift */; }; DBBC24B826A5421800398BB9 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24B726A5421800398BB9 /* CommonOSLog */; }; - DBBC24BC26A542F500398BB9 /* ThemeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BB26A542F500398BB9 /* ThemeService.swift */; }; - DBBC24C026A5443100398BB9 /* MastodonTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BE26A5443100398BB9 /* MastodonTheme.swift */; }; - DBBC24C126A5443100398BB9 /* SystemTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BF26A5443100398BB9 /* SystemTheme.swift */; }; - DBBC24C426A544B900398BB9 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24C326A544B900398BB9 /* Theme.swift */; }; - DBBC24C626A5456000398BB9 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24C326A544B900398BB9 /* Theme.swift */; }; - DBBC24C726A5456400398BB9 /* SystemTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BF26A5443100398BB9 /* SystemTheme.swift */; }; - DBBC24C826A5456400398BB9 /* ThemeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BB26A542F500398BB9 /* ThemeService.swift */; }; - DBBC24C926A5456400398BB9 /* MastodonTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BE26A5443100398BB9 /* MastodonTheme.swift */; }; DBBC24CB26A546C000398BB9 /* ThemePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */; }; - DBBC24CF26A547AE00398BB9 /* ThemeService+Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24CE26A547AE00398BB9 /* ThemeService+Appearance.swift */; }; DBBC24D126A5484F00398BB9 /* UITextView+Placeholder in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24D026A5484F00398BB9 /* UITextView+Placeholder */; }; DBBC24DC26A54BCB00398BB9 /* MastodonRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */; }; DBBC24DE26A54BCB00398BB9 /* MastodonMetricFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */; }; @@ -735,7 +733,6 @@ 2D206B9125F60EA700143C56 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = ""; }; 2D24E1222626ED9D00A59D4F /* UIView+Gesture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Gesture.swift"; sourceTree = ""; }; 2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMiddleLoaderTableViewCell.swift; sourceTree = ""; }; - 2D32EAB925CB9B0500C9ED86 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; 2D34D9D026148D9E0081BFC0 /* APIService+Recommend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Recommend.swift"; sourceTree = ""; }; 2D34D9DA261494120081BFC0 /* APIService+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Search.swift"; sourceTree = ""; }; 2D35237926256D920031AF25 /* NotificationSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSection.swift; sourceTree = ""; }; @@ -956,6 +953,16 @@ DB3667A5268AE2620027D07F /* ComposeStatusPollSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollSection.swift; sourceTree = ""; }; DB3667A7268AE2900027D07F /* ComposeStatusPollItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollItem.swift; sourceTree = ""; }; DB3D0FED25BAA42200EAA174 /* MastodonSDK */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MastodonSDK; sourceTree = ""; }; + DB3E6FDC2806A40F00B035AE /* DiscoveryHashtagsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryHashtagsViewController.swift; sourceTree = ""; }; + DB3E6FDF2806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryHashtagsViewModel.swift; sourceTree = ""; }; + DB3E6FE12806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryHashtagsViewModel+Diffable.swift"; sourceTree = ""; }; + DB3E6FE32806A5B800B035AE /* DiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverySection.swift; sourceTree = ""; }; + DB3E6FE62806A7A200B035AE /* DiscoveryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryItem.swift; sourceTree = ""; }; + DB3E6FE82806BD2200B035AE /* ThemeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeService.swift; sourceTree = ""; }; + DB3E6FEB2806D7F100B035AE /* DiscoveryNewsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryNewsViewController.swift; sourceTree = ""; }; + DB3E6FEE2806D82600B035AE /* DiscoveryNewsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryNewsViewModel.swift; sourceTree = ""; }; + DB3E6FF02806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryNewsViewModel+Diffable.swift"; sourceTree = ""; }; + DB3E6FF22806D97400B035AE /* DiscoveryNewsViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryNewsViewModel+State.swift"; sourceTree = ""; }; DB427DD225BAA00100D1B89D /* Mastodon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mastodon.app; sourceTree = BUILT_PRODUCTS_DIR; }; DB427DD525BAA00100D1B89D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DB427DD725BAA00100D1B89D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -1126,8 +1133,6 @@ DB6D9F9626367249008423CD /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; DB6F5E34264E78E7009108F4 /* AutoCompleteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteViewController.swift; sourceTree = ""; }; DB6F5E37264E994A009108F4 /* AutoCompleteTopChevronView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteTopChevronView.swift; sourceTree = ""; }; - DB71C7CA271D5A0300BE3819 /* LineChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChartView.swift; sourceTree = ""; }; - DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurveAlgorithm.swift; sourceTree = ""; }; DB71FD5125F8CCAA00512AE1 /* APIService+Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Status.swift"; sourceTree = ""; }; DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewController.swift; sourceTree = ""; }; DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewModel.swift; sourceTree = ""; }; @@ -1263,11 +1268,6 @@ DBB9759B262462E1004620BD /* ThreadMetaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadMetaView.swift; sourceTree = ""; }; DBBC24A726A52F9000398BB9 /* ComposeToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeToolbarView.swift; sourceTree = ""; }; DBBC24AB26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusContentTableViewCell.swift; sourceTree = ""; }; - DBBC24BB26A542F500398BB9 /* ThemeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeService.swift; sourceTree = ""; }; - DBBC24BE26A5443100398BB9 /* MastodonTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonTheme.swift; sourceTree = ""; }; - DBBC24BF26A5443100398BB9 /* SystemTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemTheme.swift; sourceTree = ""; }; - DBBC24C326A544B900398BB9 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; - DBBC24CE26A547AE00398BB9 /* ThemeService+Appearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThemeService+Appearance.swift"; sourceTree = ""; }; DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonRegex.swift; sourceTree = ""; }; DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonMetricFormatter.swift; sourceTree = ""; }; DBBC50C0278ED49200AF0CC6 /* MastodonAuthenticationBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonAuthenticationBox.swift; sourceTree = ""; }; @@ -1668,7 +1668,6 @@ 2D5A3D0125CF8640002347D6 /* Vender */ = { isa = PBXGroup; children = ( - DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */, 2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */, DB51D170262832380062B7A1 /* BlurHashDecode.swift */, DB51D171262832380062B7A1 /* BlurHashEncode.swift */, @@ -1687,7 +1686,6 @@ DB45FB0425CA87B4005A8AC7 /* APIService */, DB49A61925FF327D00B98345 /* EmojiService */, DB9A489B26036E19008B817C /* MastodonAttachmentService */, - DBBC24BD26A5441A00398BB9 /* ThemeService */, DB45FB0E25CA87D0005A8AC7 /* AuthenticationService.swift */, 2DA6054625F716A2006356F9 /* PlaybackState.swift */, DBC7A67B260DFADE00E57475 /* StatusPublishService.swift */, @@ -1731,6 +1729,7 @@ DB4F097626A0398000D62E92 /* Compose */, DB0617F727855B010030EE79 /* Notification */, DB4F097726A039A200D62E92 /* Search */, + DB3E6FE52806A5BA00B035AE /* Discovery */, DB0617FA27855B660030EE79 /* Settings */, DBCBED2226132E1D00B49291 /* FetchedResultsController */, ); @@ -1817,7 +1816,6 @@ isa = PBXGroup; children = ( 2DCB73FC2615C13900EC03D4 /* SearchRecommendCollectionHeader.swift */, - DB71C7CA271D5A0300BE3819 /* LineChartView.swift */, ); path = View; sourceTree = ""; @@ -2111,6 +2109,44 @@ path = Resources; sourceTree = ""; }; + DB3E6FDE2806A41200B035AE /* Hashtags */ = { + isa = PBXGroup; + children = ( + DB3E6FDC2806A40F00B035AE /* DiscoveryHashtagsViewController.swift */, + DB3E6FDF2806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift */, + DB3E6FE12806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift */, + ); + path = Hashtags; + sourceTree = ""; + }; + DB3E6FE52806A5BA00B035AE /* Discovery */ = { + isa = PBXGroup; + children = ( + DB3E6FE32806A5B800B035AE /* DiscoverySection.swift */, + DB3E6FE62806A7A200B035AE /* DiscoveryItem.swift */, + ); + path = Discovery; + sourceTree = ""; + }; + DB3E6FEA2806BD2500B035AE /* MastodonUI */ = { + isa = PBXGroup; + children = ( + DB3E6FE82806BD2200B035AE /* ThemeService.swift */, + ); + path = MastodonUI; + sourceTree = ""; + }; + DB3E6FED2806D7FC00B035AE /* News */ = { + isa = PBXGroup; + children = ( + DB3E6FEB2806D7F100B035AE /* DiscoveryNewsViewController.swift */, + DB3E6FEE2806D82600B035AE /* DiscoveryNewsViewModel.swift */, + DB3E6FF02806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift */, + DB3E6FF22806D97400B035AE /* DiscoveryNewsViewModel+State.swift */, + ); + path = News; + sourceTree = ""; + }; DB427DC925BAA00100D1B89D = { isa = PBXGroup; children = ( @@ -2706,6 +2742,7 @@ isa = PBXGroup; children = ( DB084B5125CBC56300F898ED /* CoreDataStack */, + DB3E6FEA2806BD2500B035AE /* MastodonUI */, DB6C8C0525F0921200AAA452 /* MastodonSDK */, 2DF123A625C3B0210020F248 /* ActiveLabel.swift */, 5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */, @@ -2723,7 +2760,6 @@ DBD376B1269302A4007FEC24 /* UITableViewCell.swift */, 0FAA101B25E10E760017CCDE /* UIFont.swift */, 2D206B9125F60EA700143C56 /* UIControl.swift */, - 2D32EAB925CB9B0500C9ED86 /* UIView.swift */, 5DA732CB2629CEF500A92342 /* UIView+Remove.swift */, 2D24E1222626ED9D00A59D4F /* UIView+Gesture.swift */, DB8AF55C25C138B7002E6C99 /* UIViewController.swift */, @@ -3020,18 +3056,6 @@ path = Service; sourceTree = ""; }; - DBBC24BD26A5441A00398BB9 /* ThemeService */ = { - isa = PBXGroup; - children = ( - DBBC24C326A544B900398BB9 /* Theme.swift */, - DBBC24BE26A5443100398BB9 /* MastodonTheme.swift */, - DBBC24BF26A5443100398BB9 /* SystemTheme.swift */, - DBBC24BB26A542F500398BB9 /* ThemeService.swift */, - DBBC24CE26A547AE00398BB9 /* ThemeService+Appearance.swift */, - ); - path = ThemeService; - sourceTree = ""; - }; DBBC24D526A54BCB00398BB9 /* Helper */ = { isa = PBXGroup; children = ( @@ -3087,6 +3111,8 @@ isa = PBXGroup; children = ( DBDFF19828055A0900557A48 /* Posts */, + DB3E6FDE2806A41200B035AE /* Hashtags */, + DB3E6FED2806D7FC00B035AE /* News */, DBDFF19928055A1400557A48 /* DiscoveryViewController.swift */, DBDFF19B28055BD600557A48 /* DiscoveryViewModel.swift */, ); @@ -3861,6 +3887,7 @@ DB336F43278EB1690031E64B /* MediaView+Configuration.swift in Sources */, DB66729625F9F91600D60309 /* ComposeStatusSection.swift in Sources */, DB482A3F261331E8008AE74C /* UserTimelineViewModel+State.swift in Sources */, + DB3E6FE02806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift in Sources */, 2D38F1F725CD47AC00561493 /* HomeTimelineViewModel+LoadOldestState.swift in Sources */, DB447681260B3ED600B66B82 /* CustomEmojiPickerSection.swift in Sources */, DB0FCB7427956939006C02E2 /* DataSourceFacade+Status.swift in Sources */, @@ -3924,6 +3951,7 @@ DB06180A2785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift in Sources */, DBB45B6227B51112002DC5A7 /* SuggestionAccountViewModel+Diffable.swift in Sources */, DBB3BA2A26A81C020004F2D4 /* FLAnimatedImageView.swift in Sources */, + DB3E6FF32806D97400B035AE /* DiscoveryNewsViewModel+State.swift in Sources */, DB6746ED278F45F0008A6B94 /* AutoGenerateProtocolRelayDelegate.swift in Sources */, DB0618032785A7100030EE79 /* RegisterSection.swift in Sources */, DB63F76B279A5ED300455B82 /* NotificationTimelineViewModel+LoadOldestState.swift in Sources */, @@ -3952,6 +3980,7 @@ 2D24E1232626ED9D00A59D4F /* UIView+Gesture.swift in Sources */, DBFEEC9D279C12C1004F81DD /* ProfileFieldEditCollectionViewCell.swift in Sources */, DB45FAE325CA7181005A8AC7 /* MastodonUser.swift in Sources */, + DB3E6FEC2806D7F100B035AE /* DiscoveryNewsViewController.swift in Sources */, DBA088DF26958164003EB4B2 /* UserFetchedResultsController.swift in Sources */, DB2FF510260B113300ADA9FE /* ComposeStatusPollExpiresOptionCollectionViewCell.swift in Sources */, 0F202213261351F5000C64BF /* APIService+HashtagTimeline.swift in Sources */, @@ -3993,7 +4022,6 @@ 2D4AD8A826316D3500613EFC /* SelectedAccountItem.swift in Sources */, DBE3CDFB261C6CA500430CC6 /* FavoriteViewModel.swift in Sources */, DB8AF52F25C13561002E6C99 /* DocumentStore.swift in Sources */, - DBBC24C126A5443100398BB9 /* SystemTheme.swift in Sources */, DBE3CE01261D623D00430CC6 /* FavoriteViewModel+State.swift in Sources */, 2D82BA0525E7897700E36F0F /* MastodonResendEmailViewModelNavigationDelegateShim.swift in Sources */, 2D38F1EB25CD477000561493 /* HomeTimelineViewModel+LoadLatestState.swift in Sources */, @@ -4020,6 +4048,7 @@ DB63F76227996B6600455B82 /* SearchHistoryViewController+DataSourceProvider.swift in Sources */, DB73BF4927140BA300781945 /* UICollectionViewDiffableDataSource.swift in Sources */, DBA5E7AB263BD3F5004598BB /* TimelineTableViewCellContextMenuConfiguration.swift in Sources */, + DB3E6FE92806BD2200B035AE /* ThemeService.swift in Sources */, DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */, DB63F7492799126300455B82 /* FollowerListViewController+DataSourceProvider.swift in Sources */, DB6D1B44263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift in Sources */, @@ -4056,6 +4085,7 @@ DBDFF1932805554900557A48 /* DiscoveryPostsViewModel.swift in Sources */, 2D9DB96B263A91D1007C1D71 /* APIService+DomainBlock.swift in Sources */, DBBF1DC92652538500E5B703 /* AutoCompleteSection.swift in Sources */, + DB3E6FE72806A7A200B035AE /* DiscoveryItem.swift in Sources */, DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */, DB7F48452620241000796008 /* ProfileHeaderViewModel.swift in Sources */, DB647C5926F1EA2700F7F82C /* WizardPreference.swift in Sources */, @@ -4078,6 +4108,7 @@ 5B90C462262599800002E742 /* SettingsSectionHeader.swift in Sources */, DB44768B260B3F2100B66B82 /* CustomEmojiPickerItem.swift in Sources */, 5DF1056425F887CB00D6C0D4 /* AVPlayer.swift in Sources */, + DB3E6FEF2806D82600B035AE /* DiscoveryNewsViewModel.swift in Sources */, DBBF1DCB2652539E00E5B703 /* AutoCompleteItem.swift in Sources */, DB84811727883C2600BBEABA /* MastodonRegisterPasswordHintTableViewCell.swift in Sources */, 2DA6054725F716A2006356F9 /* PlaybackState.swift in Sources */, @@ -4139,7 +4170,7 @@ DB4AA6B327BA34B6009EC082 /* CellFrameCacheContainer.swift in Sources */, DB0FCB942797E2B0006C02E2 /* SearchResultViewModel+Diffable.swift in Sources */, DB63F752279944AA00455B82 /* SearchHistorySectionHeaderCollectionReusableView.swift in Sources */, - DBBC24C426A544B900398BB9 /* Theme.swift in Sources */, + DB3E6FDD2806A40F00B035AE /* DiscoveryHashtagsViewController.swift in Sources */, DB938EED2623F79B00E5B6C1 /* ThreadViewModel.swift in Sources */, DBBC24AC26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift in Sources */, DBC7A67C260DFADE00E57475 /* StatusPublishService.swift in Sources */, @@ -4158,7 +4189,6 @@ DBBF1DC5265251C300E5B703 /* AutoCompleteViewModel+Diffable.swift in Sources */, DB603111279EB38500A935FE /* DataSourceFacade+Mute.swift in Sources */, DB68A04A25E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift in Sources */, - DBBC24BC26A542F500398BB9 /* ThemeService.swift in Sources */, DB336F38278D7AAF0031E64B /* Poll+Property.swift in Sources */, 0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */, DB6D9F8426358EEC008423CD /* SettingsItem.swift in Sources */, @@ -4171,7 +4201,6 @@ DB4FFC2C269EC39600D62E92 /* SearchTransitionController.swift in Sources */, DBA5E7A9263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift in Sources */, DBF156E22702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m in Sources */, - 2D32EABA25CB9B0500C9ED86 /* UIView.swift in Sources */, 2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */, DB6F5E35264E78E7009108F4 /* AutoCompleteViewController.swift in Sources */, DB697DE1278F5296004EF2F7 /* DataSourceFacade+Model.swift in Sources */, @@ -4179,7 +4208,6 @@ DB4F097526A037F500D62E92 /* SearchHistoryViewModel.swift in Sources */, DB6180F826391D660018D199 /* MediaPreviewingViewController.swift in Sources */, DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */, - DB71C7CB271D5A0300BE3819 /* LineChartView.swift in Sources */, DB98EB5627B0FF1B0082E365 /* ReportViewControllerAppearance.swift in Sources */, DB938F1526241FDF00E5B6C1 /* APIService+Thread.swift in Sources */, 2D206B8625F5FB0900143C56 /* Double.swift in Sources */, @@ -4201,6 +4229,7 @@ DBD376AC2692ECDB007FEC24 /* ThemePreference.swift in Sources */, DB4F097D26A03A5B00D62E92 /* SearchHistoryItem.swift in Sources */, DBD5B1FA27BD013700BD6B38 /* DataSourceProvider+StatusTableViewControllerNavigateable.swift in Sources */, + DB3E6FE22806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift in Sources */, DB68046C2636DC9E00430867 /* MastodonNotification.swift in Sources */, DBAE3F9E2616E308004B8251 /* APIService+Mute.swift in Sources */, DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */, @@ -4247,7 +4276,6 @@ DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */, DB1D61CF26F1B33600DA8662 /* WelcomeViewModel.swift in Sources */, 2DA7D04A25CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift in Sources */, - DB71C7CD271D7F4300BE3819 /* CurveAlgorithm.swift in Sources */, DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */, DB4F0966269ED52200D62E92 /* SearchResultViewModel.swift in Sources */, DBBF1DBF2652401B00E5B703 /* AutoCompleteViewModel.swift in Sources */, @@ -4264,25 +4292,25 @@ 0F2021FB2613262F000C64BF /* HashtagTimelineViewController.swift in Sources */, DB697DDD278F521D004EF2F7 /* DataSourceFacade.swift in Sources */, DBCC3B30261440A50045B23D /* UITabBarController.swift in Sources */, + DB3E6FE42806A5B800B035AE /* DiscoverySection.swift in Sources */, DB8190C62601FF0400020C08 /* AttachmentContainerView.swift in Sources */, DB697DDB278F4DE3004EF2F7 /* DataSourceProvider+StatusTableViewCellDelegate.swift in Sources */, DB51D173262832380062B7A1 /* BlurHashEncode.swift in Sources */, 2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */, DB87D4512609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift in Sources */, DBB45B5627B39FC9002DC5A7 /* MediaPreviewVideoViewController.swift in Sources */, - DBBC24C026A5443100398BB9 /* MastodonTheme.swift in Sources */, DB0FCB8027968F70006C02E2 /* MastodonStatusThreadViewModel.swift in Sources */, DB0FCB6E27950E6B006C02E2 /* MastodonMention.swift in Sources */, DB67D08627312E67006A36CF /* WizardViewController.swift in Sources */, DB6746EB278ED8B0008A6B94 /* PollOptionView+Configuration.swift in Sources */, DB9A489026035963008B817C /* APIService+Media.swift in Sources */, DBFEEC99279BDCDE004F81DD /* ProfileAboutViewModel.swift in Sources */, - DBBC24CF26A547AE00398BB9 /* ThemeService+Appearance.swift in Sources */, 2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */, DB4F097B26A039FF00D62E92 /* SearchHistorySection.swift in Sources */, DBB525302611EBF3002F1F29 /* ProfilePagingViewModel.swift in Sources */, DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */, 2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */, + DB3E6FF12806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift in Sources */, DB49A62525FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift in Sources */, DB4924E226312AB200E9DB22 /* NotificationService.swift in Sources */, DB6D9F6F2635807F008423CD /* Setting.swift in Sources */, @@ -4390,15 +4418,11 @@ DBFEF07526A69192006D7ED1 /* APIService+Media.swift in Sources */, DBFEF06F26A690C4006D7ED1 /* APIService+APIError.swift in Sources */, DBFEF05C26A57715006D7ED1 /* StatusEditorView.swift in Sources */, - DBBC24C726A5456400398BB9 /* SystemTheme.swift in Sources */, - DBBC24C826A5456400398BB9 /* ThemeService.swift in Sources */, - DBBC24C926A5456400398BB9 /* MastodonTheme.swift in Sources */, DBFEF07C26A6BD0A006D7ED1 /* APIService+Status+Publish.swift in Sources */, DBB3BA2B26A81D060004F2D4 /* FLAnimatedImageView.swift in Sources */, DB6746E8278ED639008A6B94 /* MastodonAuthenticationBox.swift in Sources */, DBBC24A826A52F9000398BB9 /* ComposeToolbarView.swift in Sources */, DBFEF05B26A57715006D7ED1 /* ComposeViewModel.swift in Sources */, - DBBC24C626A5456000398BB9 /* Theme.swift in Sources */, DBFEF06326A577F2006D7ED1 /* StatusAttachmentViewModel.swift in Sources */, DBFEF06926A67E45006D7ED1 /* AppearancePreference.swift in Sources */, DBC6461526A170AB00B0E31B /* ShareViewController.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme index 488d5a2d..048ce3cf 100644 --- a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme +++ b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme @@ -73,6 +73,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + enableAddressSanitizer = "YES" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -89,6 +90,13 @@ ReferencedContainer = "container:Mastodon.xcodeproj"> + + + + NotificationService.xcscheme_^#shared#^_ orderHint - 24 + 22 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 22 + 24 SuppressBuildableAutocreation diff --git a/Mastodon/Diffiable/Discovery/DiscoveryItem.swift b/Mastodon/Diffiable/Discovery/DiscoveryItem.swift new file mode 100644 index 00000000..181756d2 --- /dev/null +++ b/Mastodon/Diffiable/Discovery/DiscoveryItem.swift @@ -0,0 +1,15 @@ +// +// DiscoveryItem.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import Foundation +import MastodonSDK + +enum DiscoveryItem: Hashable { + case hashtag(Mastodon.Entity.Tag) + case link(Mastodon.Entity.Link) + case bottomLoader +} diff --git a/Mastodon/Diffiable/Discovery/DiscoverySection.swift b/Mastodon/Diffiable/Discovery/DiscoverySection.swift new file mode 100644 index 00000000..32683609 --- /dev/null +++ b/Mastodon/Diffiable/Discovery/DiscoverySection.swift @@ -0,0 +1,52 @@ +// +// DiscoverySection.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import UIKit +import MastodonUI + +enum DiscoverySection: CaseIterable { + // case posts + case hashtags + case news + case forYou +} + +extension DiscoverySection { + + static let logger = Logger(subsystem: "DiscoverySection", category: "logic") + + struct Configuration { } + + static func diffableDataSource( + tableView: UITableView, + context: AppContext, + configuration: Configuration + ) -> UITableViewDiffableDataSource { + tableView.register(TrendTableViewCell.self, forCellReuseIdentifier: String(describing: TrendTableViewCell.self)) + tableView.register(NewsTableViewCell.self, forCellReuseIdentifier: String(describing: NewsTableViewCell.self)) + tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self)) + + return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item in + switch item { + case .hashtag(let tag): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TrendTableViewCell.self), for: indexPath) as! TrendTableViewCell + cell.trendView.configure(tag: tag) + return cell + case .link(let link): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: NewsTableViewCell.self), for: indexPath) as! NewsTableViewCell + cell.newsView.configure(link: link) + return cell + case .bottomLoader: + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell + cell.activityIndicatorView.startAnimating() + return cell + } + } + } + +} diff --git a/Mastodon/Diffiable/Search/SearchSection.swift b/Mastodon/Diffiable/Search/SearchSection.swift index 21f1d479..4f550abf 100644 --- a/Mastodon/Diffiable/Search/SearchSection.swift +++ b/Mastodon/Diffiable/Search/SearchSection.swift @@ -21,26 +21,7 @@ extension SearchSection { ) -> UICollectionViewDiffableDataSource { let trendCellRegister = UICollectionView.CellRegistration { cell, indexPath, item in - let primaryLabelText = "#" + item.name - let secondaryLabelText = L10n.Scene.Search.Recommend.HashTag.peopleTalking(item.talkingPeopleCount ?? 0) - cell.primaryLabel.text = primaryLabelText - cell.secondaryLabel.text = secondaryLabelText - - cell.lineChartView.data = (item.history ?? []) - .sorted(by: { $0.day < $1.day }) // latest last - .map { entry in - guard let point = Int(entry.accounts) else { - return .zero - } - return CGFloat(point) - } - - cell.isAccessibilityElement = true - cell.accessibilityLabel = [ - primaryLabelText, - secondaryLabelText - ].joined(separator: ", ") } let dataSource = UICollectionViewDiffableDataSource( diff --git a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift index 2d0be696..e217d3a8 100644 --- a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift +++ b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift @@ -17,14 +17,3 @@ extension Mastodon.Entity.Tag: Hashable { } } -extension Mastodon.Entity.Tag { - - /// the sum of recent 2 days - public var talkingPeopleCount: Int? { - return history? - .prefix(2) - .compactMap { Int($0.accounts) } - .reduce(0, +) - } - -} diff --git a/Mastodon/Service/ThemeService/ThemeService+Appearance.swift b/Mastodon/Extension/MastodonUI/ThemeService.swift similarity index 97% rename from Mastodon/Service/ThemeService/ThemeService+Appearance.swift rename to Mastodon/Extension/MastodonUI/ThemeService.swift index 896ed888..5fe213d0 100644 --- a/Mastodon/Service/ThemeService/ThemeService+Appearance.swift +++ b/Mastodon/Extension/MastodonUI/ThemeService.swift @@ -1,11 +1,13 @@ // -// ThemeService+Appearance.swift +// ThemeService.swift // Mastodon // -// Created by MainasuK Cirno on 2021-7-19. +// Created by MainasuK on 2022-4-13. // import UIKit +import MastodonCommon +import MastodonUI extension ThemeService { func set(themeName: ThemeName) { diff --git a/Mastodon/Extension/UIView.swift b/Mastodon/Extension/UIView.swift deleted file mode 100644 index d4814b7e..00000000 --- a/Mastodon/Extension/UIView.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// UIView.swift -// Mastodon -// -// Created by sxiaojian on 2021/2/4. -// - -import UIKit - -// MARK: - Convenience view creation method -extension UIView { - - static let separatorColor: UIColor = { - UIColor(dynamicProvider: { collection in - switch collection.userInterfaceStyle { - case .dark: - return ThemeService.shared.currentTheme.value.separator - default: - return .separator - } - }) - }() - - static var separatorLine: UIView { - let line = UIView() - line.backgroundColor = UIView.separatorColor - return line - } - - static func separatorLineHeight(of view: UIView) -> CGFloat { - return 1.0 / view.traitCollection.displayScale - } - -} - -// MARK: - Convenience view appearance modification method -extension UIView { - @discardableResult - func applyCornerRadius(radius: CGFloat) -> Self { - layer.masksToBounds = true - layer.cornerRadius = radius - layer.cornerCurve = .continuous - return self - } - - @discardableResult - func applyShadow( - color: UIColor, - alpha: Float, - x: CGFloat, - y: CGFloat, - blur: CGFloat, - spread: CGFloat = 0) -> Self - { - layer.masksToBounds = false - layer.shadowColor = color.cgColor - layer.shadowOpacity = alpha - layer.shadowOffset = CGSize(width: x, height: y) - layer.shadowRadius = blur / 2.0 - if spread == 0 { - layer.shadowPath = nil - } else { - let dx = -spread - let rect = bounds.insetBy(dx: dx, dy: dx) - layer.shadowPath = UIBezierPath(rect: rect).cgPath - } - return self - } -} - diff --git a/Mastodon/Preference/ThemePreference.swift b/Mastodon/Preference/ThemePreference.swift index 62404779..5465cb22 100644 --- a/Mastodon/Preference/ThemePreference.swift +++ b/Mastodon/Preference/ThemePreference.swift @@ -5,17 +5,3 @@ // Created by MainasuK Cirno on 2021-7-5. // -import UIKit -import MastodonExtension - -extension UserDefaults { - - @objc dynamic var currentThemeNameRawValue: String { - get { - register(defaults: [#function: ThemeName.mastodon.rawValue]) - return string(forKey: #function) ?? ThemeName.mastodon.rawValue - } - set { self[#function] = newValue } - } - -} diff --git a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusPollOptionCollectionViewCell.swift b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusPollOptionCollectionViewCell.swift index 7ea43f15..c1869669 100644 --- a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusPollOptionCollectionViewCell.swift +++ b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusPollOptionCollectionViewCell.swift @@ -10,6 +10,7 @@ import UIKit import Combine import MastodonAsset import MastodonLocalization +import MastodonUI protocol ComposeStatusPollOptionCollectionViewCellDelegate: AnyObject { func composeStatusPollOptionCollectionViewCell(_ cell: ComposeStatusPollOptionCollectionViewCell, textFieldDidBeginEditing textField: UITextField) diff --git a/Mastodon/Scene/Discovery/DiscoveryViewController.swift b/Mastodon/Scene/Discovery/DiscoveryViewController.swift index 4f909d6c..dac2c99c 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewController.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewController.swift @@ -10,6 +10,7 @@ import UIKit import Combine import Tabman import MastodonAsset +import MastodonUI public class DiscoveryViewController: TabmanViewController, NeedsDependency { diff --git a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift index 137b8682..acb92b5f 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift @@ -13,7 +13,9 @@ final class DiscoveryViewModel { // input let context: AppContext - let discoveryViewController: DiscoveryPostsViewController + let discoveryPostsViewController: DiscoveryPostsViewController + let discoveryHashtagsViewController: DiscoveryHashtagsViewController + let discoveryNewsViewController: DiscoveryNewsViewController // output let barItems: [TMBarItemable] = { @@ -28,19 +30,37 @@ final class DiscoveryViewModel { var viewControllers: [ScrollViewContainer] { return [ - discoveryViewController, + discoveryPostsViewController, + discoveryHashtagsViewController, + discoveryNewsViewController, ] } init(context: AppContext, coordinator: SceneCoordinator) { + func setupDependency(_ needsDependency: NeedsDependency) { + needsDependency.context = context + needsDependency.coordinator = coordinator + } + self.context = context - discoveryViewController = { + discoveryPostsViewController = { let viewController = DiscoveryPostsViewController() - viewController.context = context - viewController.coordinator = coordinator + setupDependency(viewController) viewController.viewModel = DiscoveryPostsViewModel(context: context) return viewController }() + discoveryHashtagsViewController = { + let viewController = DiscoveryHashtagsViewController() + setupDependency(viewController) + viewController.viewModel = DiscoveryHashtagsViewModel(context: context) + return viewController + }() + discoveryNewsViewController = { + let viewController = DiscoveryNewsViewController() + setupDependency(viewController) + viewController.viewModel = DiscoveryNewsViewModel(context: context) + return viewController + }() // end init } diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift new file mode 100644 index 00000000..1dca1232 --- /dev/null +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift @@ -0,0 +1,113 @@ +// +// DiscoveryHashtagsViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import UIKit +import Combine +import MastodonUI + +final class DiscoveryHashtagsViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + + let logger = Logger(subsystem: "TrendPostsViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var viewModel: DiscoveryHashtagsViewModel! + + let mediaPreviewTransitionController = MediaPreviewTransitionController() + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 100 + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + return tableView + }() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension DiscoveryHashtagsViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.view.backgroundColor = theme.secondarySystemBackgroundColor + } + .store(in: &disposeBag) + + tableView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(tableView) + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + tableView.delegate = self + viewModel.setupDiffableDataSource( + tableView: tableView + ) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + tableView.deselectRow(with: transitionCoordinator, animated: animated) + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + viewModel.viewDidAppeared.send() + } + +} + +// MARK: - UITableViewDelegate +extension DiscoveryHashtagsViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(indexPath)") + guard case let .hashtag(tag) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return } + let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, hashtag: tag.name) + coordinator.present( + scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), + from: self, + transition: .show + ) + } + + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + guard let cell = cell as? TrendTableViewCell else { return } + guard let diffableDataSource = viewModel.diffableDataSource else { return } + guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } + + if let lastItem = diffableDataSource.snapshot().itemIdentifiers.last, item == lastItem { + cell.configureSeparator(style: .edge) + } + } +} + +// MARK: ScrollViewContainer +extension DiscoveryHashtagsViewController: ScrollViewContainer { + var scrollView: UIScrollView? { + tableView + } +} diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift new file mode 100644 index 00000000..0370f3f5 --- /dev/null +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift @@ -0,0 +1,42 @@ +// +// DiscoveryHashtagsViewModel+Diffable.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit + +extension DiscoveryHashtagsViewModel { + + func setupDiffableDataSource( + tableView: UITableView + ) { + diffableDataSource = DiscoverySection.diffableDataSource( + tableView: tableView, + context: context, + configuration: DiscoverySection.Configuration() + ) + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.hashtags]) + diffableDataSource?.apply(snapshot) + + $hashtags + .receive(on: DispatchQueue.main) + .sink { [weak self] hashtags in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.hashtags]) + + let items = hashtags.map { DiscoveryItem.hashtag($0) } + snapshot.appendItems(items, toSection: .hashtags) + + diffableDataSource.apply(snapshot) + } + .store(in: &disposeBag) + } + +} diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift new file mode 100644 index 00000000..5f51d645 --- /dev/null +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift @@ -0,0 +1,63 @@ +// +// DiscoveryHashtagsViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import UIKit +import Combine +import GameplayKit +import CoreData +import CoreDataStack +import MastodonSDK + +final class DiscoveryHashtagsViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + let viewDidAppeared = PassthroughSubject() + + // output + var diffableDataSource: UITableViewDiffableDataSource? + @Published var hashtags: [Mastodon.Entity.Tag] = [] + + init(context: AppContext) { + self.context = context + // end init + + Publishers.CombineLatest( + context.authenticationService.activeMastodonAuthenticationBox, + viewDidAppeared + ) + .compactMap { authenticationBox, _ -> MastodonAuthenticationBox? in + return authenticationBox + } + .throttle(for: 3, scheduler: DispatchQueue.main, latest: true) + .asyncMap { authenticationBox in + try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil) + } + .retry(3) + .map { response in Result, Error> { response } } + .catch { error in Just(Result, Error> { throw error }) } + .receive(on: DispatchQueue.main) + .sink { [weak self] result in + guard let self = self else { return } + switch result { + case .success(let response): + self.hashtags = response.value.filter { !$0.name.isEmpty } + case .failure: + break + } + } + .store(in: &disposeBag) + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift new file mode 100644 index 00000000..4042e2cd --- /dev/null +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift @@ -0,0 +1,133 @@ +// +// DiscoveryNewsViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import UIKit +import Combine +import MastodonUI + +final class DiscoveryNewsViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + + let logger = Logger(subsystem: "TrendPostsViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var viewModel: DiscoveryNewsViewModel! + + let mediaPreviewTransitionController = MediaPreviewTransitionController() + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 100 + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + return tableView + }() + + let refreshControl = UIRefreshControl() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension DiscoveryNewsViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.view.backgroundColor = theme.secondarySystemBackgroundColor + } + .store(in: &disposeBag) + + tableView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(tableView) + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + tableView.delegate = self + viewModel.setupDiffableDataSource( + tableView: tableView + ) + + tableView.refreshControl = refreshControl + refreshControl.addTarget(self, action: #selector(DiscoveryNewsViewController.refreshControlValueChanged(_:)), for: .valueChanged) + viewModel.didLoadLatest + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.refreshControl.endRefreshing() + } + .store(in: &disposeBag) + + // setup batch fetch + viewModel.listBatchFetchViewModel.setup(scrollView: tableView) + viewModel.listBatchFetchViewModel.shouldFetch + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + guard self.view.window != nil else { return } + self.viewModel.stateMachine.enter(DiscoveryNewsViewModel.State.Loading.self) + } + .store(in: &disposeBag) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + refreshControl.endRefreshing() + tableView.deselectRow(with: transitionCoordinator, animated: animated) + } + +} + +extension DiscoveryNewsViewController { + + @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { + guard viewModel.stateMachine.enter(DiscoveryNewsViewModel.State.Reloading.self) else { + sender.endRefreshing() + return + } + } + +} + +// MARK: - UITableViewDelegate +extension DiscoveryNewsViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(indexPath)") + guard case let .link(link) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return } + guard let url = URL(string: link.url) else { return } + coordinator.present( + scene: .safari(url: url), + from: self, + transition: .safariPresent(animated: true, completion: nil) + ) + } + +} + +// MARK: ScrollViewContainer +extension DiscoveryNewsViewController: ScrollViewContainer { + var scrollView: UIScrollView? { + tableView + } +} diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift new file mode 100644 index 00000000..ab3634a3 --- /dev/null +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift @@ -0,0 +1,60 @@ +// +// DiscoveryNewsViewModel+Diffable.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import Combine + +extension DiscoveryNewsViewModel { + + func setupDiffableDataSource( + tableView: UITableView + ) { + diffableDataSource = DiscoverySection.diffableDataSource( + tableView: tableView, + context: context, + configuration: DiscoverySection.Configuration() + ) + + stateMachine.enter(State.Reloading.self) + + $links + .receive(on: DispatchQueue.main) + .sink { [weak self] links in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.news]) + + let items = links.map { DiscoveryItem.link($0) } + snapshot.appendItems(items, toSection: .news) + + if let currentState = self.stateMachine.currentState { + switch currentState { + case is State.Initial, + is State.Loading, + is State.Idle, + is State.Fail: + if !items.isEmpty { + snapshot.appendItems([.bottomLoader], toSection: .news) + } + case is State.Reloading: + break + case is State.NoMore: + break + default: + assertionFailure() + break + } + } + + diffableDataSource.applySnapshot(snapshot, animated: false) + } + .store(in: &disposeBag) + } + +} diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift new file mode 100644 index 00000000..82d604d6 --- /dev/null +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift @@ -0,0 +1,209 @@ +// +// DiscoveryNewsViewModel+State.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import Foundation +import GameplayKit +import MastodonSDK + +extension DiscoveryNewsViewModel { + class State: GKState, NamingState { + + let logger = Logger(subsystem: "DiscoveryNewsViewModel.State", category: "StateMachine") + + let id = UUID() + + var name: String { + String(describing: Self.self) + } + + weak var viewModel: DiscoveryNewsViewModel? + + init(viewModel: DiscoveryNewsViewModel) { + self.viewModel = viewModel + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + let previousState = previousState as? DiscoveryNewsViewModel.State + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(self.id.uuidString)] enter \(self.name), previous: \(previousState?.name ?? "")") + } + + @MainActor + func enter(state: State.Type) { + stateMachine?.enter(state) + } + + deinit { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(self.id.uuidString)] \(self.name)") + } + } +} + +extension DiscoveryNewsViewModel.State { + class Initial: DiscoveryNewsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + } + + class Reloading: DiscoveryNewsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + viewModel.links = [] + + stateMachine.enter(Loading.self) + } + } + + class Fail: DiscoveryNewsViewModel.State { + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let _ = viewModel, let stateMachine = stateMachine else { return } + + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading 3s later…", ((#file as NSString).lastPathComponent), #line, #function) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading", ((#file as NSString).lastPathComponent), #line, #function) + stateMachine.enter(Loading.self) + } + } + } + + class Idle: DiscoveryNewsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type, is Loading.Type: + return true + default: + return false + } + } + } + + class Loading: DiscoveryNewsViewModel.State { + + var offset: Int? + var isReloading: Bool { return offset == nil } + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Fail.Type: + return true + case is Idle.Type: + return true + case is NoMore.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + + switch previousState { + case is Reloading: + offset = nil + default: + break + } + + guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else { + stateMachine.enter(Fail.self) + return + } + + let offset = self.offset + + Task { + do { + let response = try await viewModel.context.apiService.trendLinks( + domain: authenticationBox.domain, + query: Mastodon.API.Trends.StatusQuery( + offset: offset, + limit: nil + ) + ) + let newOffset: Int? = { + guard let offset = response.link?.offset else { return nil } + return self.offset.flatMap { max($0, offset) } ?? offset + }() + + let hasMore: Bool = { + guard let newOffset = newOffset else { return false } + return newOffset != self.offset // not the same one + }() + + self.offset = newOffset + + var hasNewItemsAppend = false + var links = viewModel.links + for link in response.value { + guard !links.contains(link) else { continue } + links.append(link) + hasNewItemsAppend = true + } + + if hasNewItemsAppend, hasMore { + await enter(state: Idle.self) + } else { + await enter(state: NoMore.self) + } + viewModel.links = links + viewModel.didLoadLatest.send() + } catch { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch news fail: \(error.localizedDescription)") + await enter(state: Fail.self) + viewModel.didLoadLatest.send() + } + } // end Task + } // end func + } + + class NoMore: DiscoveryNewsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + } + } +} diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift new file mode 100644 index 00000000..b87e7c05 --- /dev/null +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift @@ -0,0 +1,51 @@ +// +// DiscoveryNewsViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import UIKit +import Combine +import GameplayKit +import CoreData +import CoreDataStack +import MastodonSDK + +final class DiscoveryNewsViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + let listBatchFetchViewModel = ListBatchFetchViewModel() + + // output + @Published var links: [Mastodon.Entity.Link] = [] + var diffableDataSource: UITableViewDiffableDataSource? + private(set) lazy var stateMachine: GKStateMachine = { + let stateMachine = GKStateMachine(states: [ + State.Initial(viewModel: self), + State.Reloading(viewModel: self), + State.Fail(viewModel: self), + State.Idle(viewModel: self), + State.Loading(viewModel: self), + State.NoMore(viewModel: self), + ]) + stateMachine.enter(State.Initial.self) + return stateMachine + }() + + let didLoadLatest = PassthroughSubject() + + init(context: AppContext) { + self.context = context + // end init + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift index 3e813dbd..30e2faf9 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift @@ -30,6 +30,8 @@ final class DiscoveryPostsViewController: UIViewController, NeedsDependency, Med return tableView }() + let refreshControl = UIRefreshControl() + deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } @@ -65,6 +67,16 @@ extension DiscoveryPostsViewController { statusTableViewCellDelegate: self ) + tableView.refreshControl = refreshControl + refreshControl.addTarget(self, action: #selector(DiscoveryPostsViewController.refreshControlValueChanged(_:)), for: .valueChanged) + viewModel.didLoadLatest + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.refreshControl.endRefreshing() + } + .store(in: &disposeBag) + // setup batch fetch viewModel.listBatchFetchViewModel.setup(scrollView: tableView) viewModel.listBatchFetchViewModel.shouldFetch @@ -77,6 +89,24 @@ extension DiscoveryPostsViewController { .store(in: &disposeBag) } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + refreshControl.endRefreshing() + tableView.deselectRow(with: transitionCoordinator, animated: animated) + } + +} + +extension DiscoveryPostsViewController { + + @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { + guard viewModel.stateMachine.enter(DiscoveryPostsViewModel.State.Reloading.self) else { + sender.endRefreshing() + return + } + } + } // MARK: - UITableViewDelegate diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift index 3abb4a21..5c82384c 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift @@ -28,7 +28,7 @@ extension DiscoveryPostsViewModel { stateMachine.enter(State.Reloading.self) statusFetchedResultsController.$records - .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main) + .receive(on: DispatchQueue.main) .sink { [weak self] records in guard let self = self else { return } guard let diffableDataSource = self.diffableDataSource else { return } @@ -46,7 +46,9 @@ extension DiscoveryPostsViewModel { is State.Loading, is State.Idle, is State.Fail: - snapshot.appendItems([.bottomLoader], toSection: .main) + if !items.isEmpty { + snapshot.appendItems([.bottomLoader], toSection: .main) + } case is State.NoMore: break default: @@ -54,7 +56,7 @@ extension DiscoveryPostsViewModel { break } } - + diffableDataSource.applySnapshot(snapshot, animated: false) } .store(in: &disposeBag) diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift index 0a217868..199215d1 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift @@ -13,7 +13,7 @@ import MastodonSDK extension DiscoveryPostsViewModel { class State: GKState, NamingState { - let logger = Logger(subsystem: "TrendPostsViewModel.State", category: "StateMachine") + let logger = Logger(subsystem: "DiscoveryPostsViewModel.State", category: "StateMachine") let id = UUID() @@ -132,7 +132,6 @@ extension DiscoveryPostsViewModel.State { super.didEnter(from: previousState) guard let viewModel = viewModel, let stateMachine = stateMachine else { return } - switch previousState { case is Reloading: offset = nil @@ -182,10 +181,11 @@ extension DiscoveryPostsViewModel.State { await enter(state: NoMore.self) } viewModel.statusFetchedResultsController.statusIDs.value = statusIDs - + viewModel.didLoadLatest.send() } catch { - logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch user timeline fail: \(error.localizedDescription)") + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch posts fail: \(error.localizedDescription)") await enter(state: Fail.self) + viewModel.didLoadLatest.send() } } // end Task } // end func diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift index 100a2a34..590ccc16 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift @@ -37,6 +37,8 @@ final class DiscoveryPostsViewModel { return stateMachine }() + let didLoadLatest = PassthroughSubject() + init(context: AppContext) { self.context = context self.statusFetchedResultsController = StatusFetchedResultsController( diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index 7b7f35e5..54955272 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -17,6 +17,7 @@ import AlamofireImage import StoreKit import MastodonAsset import MastodonLocalization +import MastodonUI final class HomeTimelineViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { @@ -291,7 +292,7 @@ extension HomeTimelineViewController { tableView.deselectRow(with: transitionCoordinator, animated: animated) // needs trigger manually after onboarding dismiss - setNeedsStatusBarAppearanceUpdate() + setNeedsStatusBarAppearanceUpdate() } override func viewDidAppear(_ animated: Bool) { diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index db50565a..f470082f 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -11,6 +11,7 @@ import Combine import SafariServices import MastodonAsset import MastodonLocalization +import MastodonUI class MainTabBarController: UITabBarController { diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index 6568ab0c..7ac0f6e5 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -9,6 +9,7 @@ import os.log import UIKit import Combine import CoreDataStack +import MastodonUI protocol SidebarViewControllerDelegate: AnyObject { func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) diff --git a/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift b/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift index a43d65df..379cba70 100644 --- a/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift +++ b/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift @@ -9,45 +9,13 @@ import UIKit import Combine import MetaTextKit import MastodonAsset +import MastodonUI final class TrendCollectionViewCell: UICollectionViewCell { var _disposeBag = Set() - let container: UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.spacing = 16 - return stackView - }() - - let infoContainer: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - return stackView - }() - - let lineChartContainer: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - return stackView - }() - - let primaryLabel: UILabel = { - let label = UILabel() - label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) - label.textColor = Asset.Colors.Label.primary.color - return label - }() - - let secondaryLabel: UILabel = { - let label = UILabel() - label.font = UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular)) - label.textColor = Asset.Colors.Label.secondary.color - return label - }() - - let lineChartView = LineChartView() + let trendView = TrendView() override func prepareForReuse() { super.prepareForReuse() @@ -77,44 +45,13 @@ extension TrendCollectionViewCell { } .store(in: &_disposeBag) - container.translatesAutoresizingMaskIntoConstraints = false - contentView.addSubview(container) + trendView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(trendView) NSLayoutConstraint.activate([ - container.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 11), - container.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), - container.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), - contentView.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: 11), - ]) - - container.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) - container.isLayoutMarginsRelativeArrangement = true - - // container: H - [ info container | padding | line chart container ] - container.addArrangedSubview(infoContainer) - - // info container: V - [ primary | secondary ] - infoContainer.addArrangedSubview(primaryLabel) - infoContainer.addArrangedSubview(secondaryLabel) - - // padding - let padding = UIView() - container.addArrangedSubview(padding) - - // line chart - container.addArrangedSubview(lineChartContainer) - - let lineChartViewTopPadding = UIView() - let lineChartViewBottomPadding = UIView() - lineChartViewTopPadding.translatesAutoresizingMaskIntoConstraints = false - lineChartViewBottomPadding.translatesAutoresizingMaskIntoConstraints = false - lineChartView.translatesAutoresizingMaskIntoConstraints = false - lineChartContainer.addArrangedSubview(lineChartViewTopPadding) - lineChartContainer.addArrangedSubview(lineChartView) - lineChartContainer.addArrangedSubview(lineChartViewBottomPadding) - NSLayoutConstraint.activate([ - lineChartView.widthAnchor.constraint(equalToConstant: 50), - lineChartView.heightAnchor.constraint(equalToConstant: 26), - lineChartViewTopPadding.heightAnchor.constraint(equalTo: lineChartViewBottomPadding.heightAnchor), + trendView.topAnchor.constraint(equalTo: contentView.topAnchor), + trendView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + trendView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + trendView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), ]) } diff --git a/Mastodon/Scene/Search/SearchDetail/SearchHistory/View/SearchHistoryTableHeaderView.swift b/Mastodon/Scene/Search/SearchDetail/SearchHistory/View/SearchHistoryTableHeaderView.swift index 8ac661b1..fc41bdf2 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchHistory/View/SearchHistoryTableHeaderView.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchHistory/View/SearchHistoryTableHeaderView.swift @@ -10,6 +10,7 @@ import UIKit import Combine import MastodonAsset import MastodonLocalization +import MastodonUI protocol SearchHistoryTableHeaderViewDelegate: AnyObject { func searchHistoryTableHeaderView(_ searchHistoryTableHeaderView: SearchHistoryTableHeaderView, clearSearchHistoryButtonDidPressed button: UIButton) diff --git a/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift b/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift index 78c5462f..8300f865 100644 --- a/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift +++ b/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift @@ -11,6 +11,7 @@ import Combine import UIKit import MastodonAsset import MastodonLocalization +import MastodonUI protocol ContentWarningOverlayViewDelegate: AnyObject { func contentWarningOverlayViewDidPressed(_ contentWarningOverlayView: ContentWarningOverlayView) diff --git a/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift b/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift index ad2fa398..cba1fcf6 100644 --- a/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift +++ b/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift @@ -58,7 +58,7 @@ extension MediaView { }() if let previewURL = configuration.previewURL, - let url = URL(string: previewURL) + let url = URL(string: previewURL) { let placeholder = UIImage.placeholder(color: .systemGray6) let request = URLRequest(url: url) diff --git a/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift b/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift index c339654f..0953feec 100644 --- a/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift +++ b/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift @@ -6,6 +6,7 @@ // import UIKit +import MastodonUI final class ThreadMetaView: UIView { diff --git a/Mastodon/Service/APIService/APIService+Trend.swift b/Mastodon/Service/APIService/APIService+Trend.swift index 34edae09..47dda6bd 100644 --- a/Mastodon/Service/APIService/APIService+Trend.swift +++ b/Mastodon/Service/APIService/APIService+Trend.swift @@ -53,4 +53,17 @@ extension APIService { return response } + func trendLinks( + domain: String, + query: Mastodon.API.Trends.LinkQuery + ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Link]> { + let response = try await Mastodon.API.Trends.links( + session: session, + domain: domain, + query: query + ).singleOutput() + + return response + } + } diff --git a/Mastodon/Service/SettingService.swift b/Mastodon/Service/SettingService.swift index 1e8022c5..bd571d8f 100644 --- a/Mastodon/Service/SettingService.swift +++ b/Mastodon/Service/SettingService.swift @@ -12,6 +12,7 @@ import CoreDataStack import MastodonSDK import MastodonAsset import MastodonLocalization +import MastodonCommon final class SettingService { @@ -190,18 +191,6 @@ extension SettingService { extension SettingService { static func updatePreference(setting: Setting) { - // set appearance -// let userInterfaceStyle: UIUserInterfaceStyle = { -// switch setting.appearance { -// case .automatic: return .unspecified -// case .light: return .light -// case .dark: return .dark -// } -// }() -// if UserDefaults.shared.customUserInterfaceStyle != userInterfaceStyle { -// UserDefaults.shared.customUserInterfaceStyle = userInterfaceStyle -// } - // set theme let themeName: ThemeName = setting.preferredTrueBlackDarkMode ? .system : .mastodon if UserDefaults.shared.currentThemeNameRawValue != themeName.rawValue { @@ -223,6 +212,6 @@ extension SettingService { if UserDefaults.shared.preferredUsingDefaultBrowser != setting.preferredUsingDefaultBrowser { UserDefaults.shared.preferredUsingDefaultBrowser = setting.preferredUsingDefaultBrowser } - } + } diff --git a/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Theme.swift b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Theme.swift new file mode 100644 index 00000000..a87a8da7 --- /dev/null +++ b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Theme.swift @@ -0,0 +1,26 @@ +// +// Preference+Theme.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import MastodonExtension + +public enum ThemeName: String, CaseIterable { + case system + case mastodon +} + +extension UserDefaults { + + @objc public dynamic var currentThemeNameRawValue: String { + get { + register(defaults: [#function: ThemeName.mastodon.rawValue]) + return string(forKey: #function) ?? ThemeName.mastodon.rawValue + } + set { self[#function] = newValue } + } + +} diff --git a/MastodonSDK/Sources/MastodonExtension/UIView.swift b/MastodonSDK/Sources/MastodonExtension/UIView.swift index 5466c464..f96d1618 100644 --- a/MastodonSDK/Sources/MastodonExtension/UIView.swift +++ b/MastodonSDK/Sources/MastodonExtension/UIView.swift @@ -12,3 +12,37 @@ extension UIView { return UIScreen.main.scale != UIScreen.main.nativeScale } } + +extension UIView { + @discardableResult + public func applyCornerRadius(radius: CGFloat) -> Self { + layer.masksToBounds = true + layer.cornerRadius = radius + layer.cornerCurve = .continuous + return self + } + + @discardableResult + public func applyShadow( + color: UIColor, + alpha: Float, + x: CGFloat, + y: CGFloat, + blur: CGFloat, + spread: CGFloat = 0 + ) -> Self { + layer.masksToBounds = false + layer.shadowColor = color.cgColor + layer.shadowOpacity = alpha + layer.shadowOffset = CGSize(width: x, height: y) + layer.shadowRadius = blur / 2.0 + if spread == 0 { + layer.shadowPath = nil + } else { + let dx = -spread + let rect = bounds.insetBy(dx: dx, dy: dx) + layer.shadowPath = UIBezierPath(rect: rect).cgPath + } + return self + } +} diff --git a/MastodonSDK/Sources/MastodonExtension/UInt64.swift b/MastodonSDK/Sources/MastodonExtension/UInt64.swift new file mode 100644 index 00000000..03dfbaca --- /dev/null +++ b/MastodonSDK/Sources/MastodonExtension/UInt64.swift @@ -0,0 +1,12 @@ +// +// UInt64.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import Foundation + +extension UInt64 { + public static let second: UInt64 = 1_000_000_000 +} diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift index 25e130e3..d2dca824 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift @@ -71,9 +71,9 @@ extension Mastodon.API.Trends { .appendingPathComponent("statuses") } - /// Trending tags + /// Trending status /// - /// Tags that are being used more frequently within the past week. + /// TBD /// /// Version history: /// 3.?.? @@ -83,7 +83,7 @@ extension Mastodon.API.Trends { /// - session: `URLSession` /// - domain: Mastodon instance domain. e.g. "example.com" /// - query: query - /// - Returns: `AnyPublisher` contains `Hashtags` nested in the response + /// - Returns: `[Status]` nested in the response public static func statuses( session: URLSession, @@ -126,3 +126,47 @@ extension Mastodon.API.Trends { } } + +extension Mastodon.API.Trends { + + static func trendLinksURL(domain: String) -> URL { + Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("trends") + .appendingPathComponent("links") + } + + /// Trending links + /// + /// TBD + /// + /// Version history: + /// 3.?.? + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/instance/trends/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - query: query + /// - Returns: `[Link]` nested in the response + + public static func links( + session: URLSession, + domain: String, + query: Mastodon.API.Trends.LinkQuery? + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: trendLinksURL(domain: domain), + query: query, + authorization: nil + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: [Mastodon.Entity.Link].self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + + public typealias LinkQuery = StatusQuery + +} diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Link.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Link.swift new file mode 100644 index 00000000..d1d7bd67 --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Link.swift @@ -0,0 +1,54 @@ +// +// Mastodon+Entity+Link.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import Foundation + +extension Mastodon.Entity { + /// History + /// + /// - Since: 3.5.0 + /// - Version: 3.5.1 + /// # Last Update + /// 2022/4/13 + /// # Reference + /// [Document](TBD) + public struct Link: Codable { + public let url: String + public let title: String + public let description: String + public let providerName: String + public let providerURL: String + public let image: String + public let width: Int + public let height: Int + public let blurhash: String + public let history: [History] + + enum CodingKeys: String, CodingKey { + case url + case title + case description + case providerName = "provider_name" + case providerURL = "provider_url" + case image + case width + case height + case blurhash + case history + } + } +} + +extension Mastodon.Entity.Link: Hashable { + public static func == (lhs: Mastodon.Entity.Link, rhs: Mastodon.Entity.Link) -> Bool { + return lhs.url == rhs.url + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(url) + } +} diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift index b017d155..84875359 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift @@ -37,6 +37,7 @@ extension Mastodon.Entity { public func hash(into hasher: inout Hasher) { hasher.combine(name) + hasher.combine(url) } } } diff --git a/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Link.swift b/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Link.swift new file mode 100644 index 00000000..8f00911f --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Link.swift @@ -0,0 +1,21 @@ +// +// Mastodon+Entity+Link.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import Foundation +import MastodonSDK + +extension Mastodon.Entity.Link { + + /// the sum of recent 2 days + public var talkingPeopleCount: Int? { + return history + .prefix(2) + .compactMap { Int($0.accounts) } + .reduce(0, +) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Tag.swift b/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Tag.swift new file mode 100644 index 00000000..4d58145e --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Tag.swift @@ -0,0 +1,21 @@ +// +// Mastodon+Entity+Tag.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import Foundation +import MastodonSDK + +extension Mastodon.Entity.Tag { + + /// the sum of recent 2 days + public var talkingPeopleCount: Int? { + return history? + .prefix(2) + .compactMap { Int($0.accounts) } + .reduce(0, +) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/Extension/UIView.swift b/MastodonSDK/Sources/MastodonUI/Extension/UIView.swift new file mode 100644 index 00000000..0489965b --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/UIView.swift @@ -0,0 +1,34 @@ +// +// UIView.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit + +extension UIView { + + static let separatorColor: UIColor = { + UIColor(dynamicProvider: { collection in + switch collection.userInterfaceStyle { + case .dark: + return ThemeService.shared.currentTheme.value.separator + default: + return .separator + } + }) + }() + + + public static var separatorLine: UIView { + let line = UIView() + line.backgroundColor = UIView.separatorColor + return line + } + + public static func separatorLineHeight(of view: UIView) -> CGFloat { + return 1.0 / view.traitCollection.displayScale + } + +} diff --git a/Mastodon/Service/ThemeService/MastodonTheme.swift b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/MastodonTheme.swift similarity index 98% rename from Mastodon/Service/ThemeService/MastodonTheme.swift rename to MastodonSDK/Sources/MastodonUI/Service/ThemeService/MastodonTheme.swift index 0dad463b..76173590 100644 --- a/Mastodon/Service/ThemeService/MastodonTheme.swift +++ b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/MastodonTheme.swift @@ -7,6 +7,7 @@ import UIKit import MastodonAsset +import MastodonCommon struct MastodonTheme: Theme { diff --git a/Mastodon/Service/ThemeService/SystemTheme.swift b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/SystemTheme.swift similarity index 98% rename from Mastodon/Service/ThemeService/SystemTheme.swift rename to MastodonSDK/Sources/MastodonUI/Service/ThemeService/SystemTheme.swift index 7796fde7..cea10a28 100644 --- a/Mastodon/Service/ThemeService/SystemTheme.swift +++ b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/SystemTheme.swift @@ -7,6 +7,7 @@ import UIKit import MastodonAsset +import MastodonCommon struct SystemTheme: Theme { diff --git a/Mastodon/Service/ThemeService/Theme.swift b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/Theme.swift similarity index 82% rename from Mastodon/Service/ThemeService/Theme.swift rename to MastodonSDK/Sources/MastodonUI/Service/ThemeService/Theme.swift index 1a3b3c5d..ae555da0 100644 --- a/Mastodon/Service/ThemeService/Theme.swift +++ b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/Theme.swift @@ -6,6 +6,7 @@ // import UIKit +import MastodonCommon public protocol Theme { @@ -42,17 +43,3 @@ public protocol Theme { var notificationStatusBorderColor: UIColor { get } } - -public enum ThemeName: String, CaseIterable { - case system - case mastodon -} - -extension ThemeName { - public var theme: Theme { - switch self { - case .system: return SystemTheme() - case .mastodon: return MastodonTheme() - } - } -} diff --git a/Mastodon/Service/ThemeService/ThemeService.swift b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/ThemeService.swift similarity index 57% rename from Mastodon/Service/ThemeService/ThemeService.swift rename to MastodonSDK/Sources/MastodonUI/Service/ThemeService/ThemeService.swift index b356d346..b782c413 100644 --- a/Mastodon/Service/ThemeService/ThemeService.swift +++ b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/ThemeService.swift @@ -8,16 +8,17 @@ import UIKit import Combine import AppShared +import MastodonCommon // ref: https://zamzam.io/protocol-oriented-themes-for-ios-apps/ -final class ThemeService { +public final class ThemeService { - static let tintColor: UIColor = .label + public static let tintColor: UIColor = .label // MARK: - Singleton public static let shared = ThemeService() - let currentTheme: CurrentValueSubject + public let currentTheme: CurrentValueSubject private init() { let theme = ThemeName(rawValue: UserDefaults.shared.currentThemeNameRawValue)?.theme ?? ThemeName.mastodon.theme @@ -25,3 +26,12 @@ final class ThemeService { } } + +extension ThemeName { + public var theme: Theme { + switch self { + case .system: return SystemTheme() + case .mastodon: return MastodonTheme() + } + } +} diff --git a/Mastodon/Vender/CurveAlgorithm.swift b/MastodonSDK/Sources/MastodonUI/Vendor/CurveAlgorithm.swift similarity index 100% rename from Mastodon/Vender/CurveAlgorithm.swift rename to MastodonSDK/Sources/MastodonUI/Vendor/CurveAlgorithm.swift diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift new file mode 100644 index 00000000..3116534a --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift @@ -0,0 +1,43 @@ +// +// NewsView+Configuration.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import MastodonSDK +import MastodonLocalization +import AlamofireImage + +extension NewsView { + public func configure(link: Mastodon.Entity.Link) { + providerNameLabel.text = link.providerName + headlineLabel.text = link.title + footnoteLabel.text = L10n.Scene.Search.Recommend.HashTag.peopleTalking(link.talkingPeopleCount ?? 0) + + let configuration = MediaView.Configuration( + info: .image(info: .init( + aspectRadio: CGSize(width: link.width, height: link.height), + assetURL: link.image + )), + blurhash: link.blurhash + ) + imageView.setup(configuration: configuration) + + if let previewURL = configuration.previewURL, + let url = URL(string: previewURL) + { + let placeholder = UIImage.placeholder(color: .systemGray6) + let request = URLRequest(url: url) + ImageDownloader.default.download(request, completion: { response in + switch response.result { + case .success(let image): + configuration.previewImage = image + case .failure: + configuration.previewImage = placeholder + } + }) + } + } // end func +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift new file mode 100644 index 00000000..ee9506a9 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift @@ -0,0 +1,102 @@ +// +// NewsView.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import MastodonAsset + +public final class NewsView: UIView { + + let container = UIStackView() + + let providerNameLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .semibold)) + label.textColor = Asset.Colors.Label.primary.color + return label + }() + + let headlineLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)) + label.textColor = Asset.Colors.Label.primary.color + label.numberOfLines = 0 + return label + }() + + let footnoteLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .caption1).scaledFont(for: .systemFont(ofSize: 12, weight: .medium)) + label.textColor = Asset.Colors.Label.secondary.color + return label + }() + + let imageView = MediaView() + + public func prepareForReuse() { + imageView.prepareForReuse() + } + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension NewsView { + private func _init() { + // container: H - [ textContainer | imageView ] + container.axis = .horizontal + container.spacing = 8 + container.translatesAutoresizingMaskIntoConstraints = false + addSubview(container) + NSLayoutConstraint.activate([ + container.topAnchor.constraint(equalTo: topAnchor), + container.leadingAnchor.constraint(equalTo: leadingAnchor), + container.trailingAnchor.constraint(equalTo: trailingAnchor), + container.bottomAnchor.constraint(equalTo: bottomAnchor), + ]) + + // textContainer: V - [ providerContainer | headlineLabel | (spacer) | footnoteLabel ] + let textContainer = UIStackView() + textContainer.axis = .vertical + textContainer.spacing = 4 + container.addArrangedSubview(textContainer) + + // providerContainer: H - [ providerFavIconImageView | providerNameLabel | (spacer) ] + let providerContainer = UIStackView() + providerContainer.axis = .horizontal + textContainer.addArrangedSubview(providerContainer) + + providerContainer.addArrangedSubview(providerNameLabel) + + // headlineLabel + textContainer.addArrangedSubview(headlineLabel) + let spacer = UIView() + spacer.translatesAutoresizingMaskIntoConstraints = false + textContainer.addArrangedSubview(spacer) + NSLayoutConstraint.activate([ + spacer.heightAnchor.constraint(equalToConstant: 24).priority(.required - 1), + ]) + // footnoteLabel + textContainer.addArrangedSubview(footnoteLabel) + + // imageView + imageView.translatesAutoresizingMaskIntoConstraints = false + container.addArrangedSubview(imageView) + NSLayoutConstraint.activate([ + imageView.widthAnchor.constraint(equalToConstant: 132).priority(.required - 1), + ]) + imageView.isUserInteractionEnabled = false + } +} + diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift new file mode 100644 index 00000000..cdd3dfd8 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift @@ -0,0 +1,35 @@ +// +// TrendView+Configuration.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import MastodonSDK +import MastodonLocalization + +extension TrendView { + public func configure(tag: Mastodon.Entity.Tag) { + let primaryLabelText = "#" + tag.name + let secondaryLabelText = L10n.Scene.Search.Recommend.HashTag.peopleTalking(tag.talkingPeopleCount ?? 0) + + primaryLabel.text = primaryLabelText + secondaryLabel.text = secondaryLabelText + + lineChartView.data = (tag.history ?? []) + .sorted(by: { $0.day < $1.day }) // latest last + .map { entry in + guard let point = Int(entry.accounts) else { + return .zero + } + return CGFloat(point) + } + + isAccessibilityElement = true + accessibilityLabel = [ + primaryLabelText, + secondaryLabelText + ].joined(separator: ", ") + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/TrendView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView.swift new file mode 100644 index 00000000..ff1b9b70 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView.swift @@ -0,0 +1,100 @@ +// +// TrendView.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import MastodonAsset + +public final class TrendView: UIView { + + let container: UIStackView = { + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.spacing = 16 + return stackView + }() + + let infoContainer: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + return stackView + }() + + let lineChartContainer: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + return stackView + }() + + let primaryLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) + label.textColor = Asset.Colors.Label.primary.color + return label + }() + + let secondaryLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular)) + label.textColor = Asset.Colors.Label.secondary.color + return label + }() + + let lineChartView = LineChartView() + + public override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension TrendView { + private func _init() { + container.translatesAutoresizingMaskIntoConstraints = false + addSubview(container) + NSLayoutConstraint.activate([ + container.topAnchor.constraint(equalTo: topAnchor, constant: 11), + container.leadingAnchor.constraint(equalTo: leadingAnchor), + container.trailingAnchor.constraint(equalTo: trailingAnchor), + bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: 11), + ]) + + // container: H - [ info container | padding | line chart container ] + container.addArrangedSubview(infoContainer) + + // info container: V - [ primary | secondary ] + infoContainer.addArrangedSubview(primaryLabel) + infoContainer.addArrangedSubview(secondaryLabel) + + // padding + let padding = UIView() + container.addArrangedSubview(padding) + + // line chart + container.addArrangedSubview(lineChartContainer) + + let lineChartViewTopPadding = UIView() + let lineChartViewBottomPadding = UIView() + lineChartViewTopPadding.translatesAutoresizingMaskIntoConstraints = false + lineChartViewBottomPadding.translatesAutoresizingMaskIntoConstraints = false + lineChartView.translatesAutoresizingMaskIntoConstraints = false + lineChartContainer.addArrangedSubview(lineChartViewTopPadding) + lineChartContainer.addArrangedSubview(lineChartView) + lineChartContainer.addArrangedSubview(lineChartViewBottomPadding) + NSLayoutConstraint.activate([ + lineChartView.widthAnchor.constraint(equalToConstant: 50), + lineChartView.heightAnchor.constraint(equalToConstant: 26), + lineChartViewTopPadding.heightAnchor.constraint(equalTo: lineChartViewBottomPadding.heightAnchor), + ]) + } +} + diff --git a/Mastodon/Scene/Search/Search/View/LineChartView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/LineChartView.swift similarity index 85% rename from Mastodon/Scene/Search/Search/View/LineChartView.swift rename to MastodonSDK/Sources/MastodonUI/View/Control/LineChartView.swift index cd76fb0c..c90b59f0 100644 --- a/Mastodon/Scene/Search/Search/View/LineChartView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/LineChartView.swift @@ -7,12 +7,11 @@ import UIKit import Accelerate -import simd import MastodonAsset -final class LineChartView: UIView { +public final class LineChartView: UIView { - var data: [CGFloat] = [] { + public var data: [CGFloat] = [] { didSet { setNeedsLayout() } @@ -20,14 +19,13 @@ final class LineChartView: UIView { let lineShapeLayer = CAShapeLayer() let gradientLayer = CAGradientLayer() -// let dotShapeLayer = CAShapeLayer() - override init(frame: CGRect) { + public override init(frame: CGRect) { super.init(frame: frame) _init() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) _init() } @@ -38,10 +36,8 @@ extension LineChartView { private func _init() { lineShapeLayer.frame = bounds gradientLayer.frame = bounds -// dotShapeLayer.frame = bounds layer.addSublayer(lineShapeLayer) layer.addSublayer(gradientLayer) -// layer.addSublayer(dotShapeLayer) gradientLayer.colors = [ Asset.Colors.brandBlue.color.withAlphaComponent(0.5).cgColor, // set the same alpha to fill @@ -51,16 +47,14 @@ extension LineChartView { gradientLayer.endPoint = CGPoint(x: 0.5, y: 1) } - override func layoutSubviews() { + public override func layoutSubviews() { super.layoutSubviews() lineShapeLayer.frame = bounds gradientLayer.frame = bounds -// dotShapeLayer.frame = bounds guard data.count > 1 else { lineShapeLayer.path = nil -// dotShapeLayer.path = nil gradientLayer.isHidden = true return } @@ -113,9 +107,5 @@ extension LineChartView { maskLayer.strokeColor = UIColor.clear.cgColor maskLayer.lineWidth = 0.0 gradientLayer.mask = maskLayer - -// dotShapeLayer.lineWidth = 3 -// dotShapeLayer.fillColor = Asset.Colors.brandBlue.color.cgColor -// dotShapeLayer.path = dotPath.cgPath } } diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift new file mode 100644 index 00000000..3515000f --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift @@ -0,0 +1,56 @@ +// +// NewsTableViewCell.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit + +public final class NewsTableViewCell: UITableViewCell { + + public let newsView = NewsView() + + let separatorLine = UIView.separatorLine + + public override func prepareForReuse() { + super.prepareForReuse() + + newsView.prepareForReuse() + } + + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + _init() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension NewsTableViewCell { + + private func _init() { + newsView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(newsView) + NSLayoutConstraint.activate([ + newsView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), + newsView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + newsView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), + contentView.bottomAnchor.constraint(equalTo: newsView.bottomAnchor, constant: 16), + ]) + + separatorLine.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(separatorLine) + NSLayoutConstraint.activate([ + separatorLine.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), + ]) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/TrendTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/TrendTableViewCell.swift new file mode 100644 index 00000000..8c1cebff --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/TrendTableViewCell.swift @@ -0,0 +1,86 @@ +// +// TrendTableViewCell.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit + +public final class TrendTableViewCell: UITableViewCell { + + public let trendView = TrendView() + + let separatorLine = UIView.separatorLine + + public override func prepareForReuse() { + super.prepareForReuse() + + configureSeparator(style: .inset) + } + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension TrendTableViewCell { + + private func _init() { + trendView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(trendView) + NSLayoutConstraint.activate([ + trendView.topAnchor.constraint(equalTo: contentView.topAnchor), + trendView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + trendView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), + trendView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + + configureSeparator(style: .inset) + + accessibilityElements = [trendView] + } + +} + +extension TrendTableViewCell { + + public enum SeparatorStyle { + case edge + case inset + } + + public func configureSeparator(style: SeparatorStyle) { + separatorLine.removeFromSuperview() + separatorLine.removeConstraints(separatorLine.constraints) + + switch style { + case .edge: + separatorLine.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(separatorLine) + NSLayoutConstraint.activate([ + separatorLine.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), + ]) + case .inset: + separatorLine.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(separatorLine) + NSLayoutConstraint.activate([ + separatorLine.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), + ]) + } + } + +} diff --git a/ShareActionExtension/Scene/ShareViewController.swift b/ShareActionExtension/Scene/ShareViewController.swift index d45558f1..622e0106 100644 --- a/ShareActionExtension/Scene/ShareViewController.swift +++ b/ShareActionExtension/Scene/ShareViewController.swift @@ -12,6 +12,7 @@ import MastodonUI import SwiftUI import MastodonAsset import MastodonLocalization +import MastodonUI class ShareViewController: UIViewController { diff --git a/ShareActionExtension/Scene/ShareViewModel.swift b/ShareActionExtension/Scene/ShareViewModel.swift index fbad8220..c56f8ecf 100644 --- a/ShareActionExtension/Scene/ShareViewModel.swift +++ b/ShareActionExtension/Scene/ShareViewModel.swift @@ -16,6 +16,7 @@ import SwiftUI import UniformTypeIdentifiers import MastodonAsset import MastodonLocalization +import MastodonUI final class ShareViewModel { diff --git a/ShareActionExtension/Scene/View/ComposeToolbarView.swift b/ShareActionExtension/Scene/View/ComposeToolbarView.swift index 73caac73..a903d3eb 100644 --- a/ShareActionExtension/Scene/View/ComposeToolbarView.swift +++ b/ShareActionExtension/Scene/View/ComposeToolbarView.swift @@ -12,6 +12,7 @@ import MastodonSDK import MastodonUI import MastodonAsset import MastodonLocalization +import MastodonUI protocol ComposeToolbarViewDelegate: AnyObject { func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: UIButton) From 8e0d526708f93c8c463137832192bdaafcd41cb7 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 13 Apr 2022 20:54:34 +0800 Subject: [PATCH 125/188] chore: fix CI build issue --- MastodonSDK/Package.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index af27091f..d6078090 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -60,7 +60,9 @@ let package = Package( ), .target( name: "MastodonCommon", - dependencies: [] + dependencies: [ + "MastodonExtension" + ] ), .target( name: "MastodonExtension", From b0fca49413c220f4b1c0a77c9ec7bf8507ab4258 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 14 Apr 2022 21:15:21 +0800 Subject: [PATCH 126/188] feat: add For You tab for Discovery scene --- Mastodon.xcodeproj/project.pbxproj | 42 ++- .../xcschemes/xcschememanagement.plist | 4 +- .../Diffiable/Discovery/DiscoveryItem.swift | 2 + .../Discovery/DiscoverySection.swift | 14 +- .../CoreDataStack/MastodonUser.swift | 47 ---- .../Persistence/Extension/MastodonEmoji.swift | 10 - .../Scene/Discovery/DiscoveryViewModel.swift | 8 + .../DiscoveryForYouViewController.swift | 127 +++++++++ .../DiscoveryForYouViewModel+Diffable.swift | 43 +++ .../ForYou/DiscoveryForYouViewModel.swift | 75 ++++++ .../News/DiscoveryNewsViewModel+State.swift | 6 +- .../Posts/DiscoveryPostsViewModel+State.swift | 8 +- Mastodon/Scene/Profile/ProfileViewModel.swift | 98 +------ .../APIService/APIService+Recommend.swift | 5 +- MastodonSDK/Package.swift | 1 + .../Scene/Discovery/Contents.json | 9 + .../Contents.json | 38 +++ .../MastodonAsset/Generated/Assets.swift | 3 + .../Preference/Preference+Appearance.swift | 6 +- .../API/Mastodon+API+Suggestions.swift | 2 +- .../API/Mastodon+API+V2+Suggestions.swift | 2 +- .../CoreDataStack/MastodonEmoji.swift | 20 ++ .../CoreDataStack/MastodonUser.swift | 57 ++++ .../MastodonUI/Extension/MetaLabel.swift | 12 +- .../Helper/MastodonMetricFormatter.swift | 4 +- .../ProfileCardView+Configuration.swift | 88 ++++++ .../Content/ProfileCardView+ViewModel.swift | 148 ++++++++++ .../View/Content/ProfileCardView.swift | 235 ++++++++++++++++ .../View/Content/StatusView+ViewModel.swift | 1 + .../ProfileRelationshipActionButton.swift | 18 +- .../ProfileStatusDashboardMeterView.swift | 10 +- .../Control}/ProfileStatusDashboardView.swift | 20 +- .../ProfileCardTableViewCell.swift | 68 +++++ .../ViewModel/RelationshipViewModel.swift | 253 ++++++++++++++++++ 34 files changed, 1261 insertions(+), 223 deletions(-) create mode 100644 Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift create mode 100644 Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift create mode 100644 Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/profile.card.background.colorset/Contents.json rename Mastodon/Preference/AppearancePreference.swift => MastodonSDK/Sources/MastodonCommon/Preference/Preference+Appearance.swift (81%) create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonEmoji.swift create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonUser.swift rename {Mastodon => MastodonSDK/Sources/MastodonUI}/Helper/MastodonMetricFormatter.swift (95%) create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+Configuration.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift rename {Mastodon/Scene/Profile/Header/View => MastodonSDK/Sources/MastodonUI/View/Control}/ProfileRelationshipActionButton.swift (80%) rename {Mastodon/Scene/Profile/Header/View => MastodonSDK/Sources/MastodonUI/View/Control}/ProfileStatusDashboardMeterView.swift (91%) rename {Mastodon/Scene/Profile/Header/View => MastodonSDK/Sources/MastodonUI/View/Control}/ProfileStatusDashboardView.swift (85%) create mode 100644 MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift create mode 100644 MastodonSDK/Sources/MastodonUI/ViewModel/RelationshipViewModel.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 73332bab..678fc710 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -214,7 +214,6 @@ DB336F3F278E668C0031E64B /* StatusTableViewCell+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB336F3E278E668C0031E64B /* StatusTableViewCell+ViewModel.swift */; }; DB336F41278E68480031E64B /* StatusView+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB336F40278E68480031E64B /* StatusView+Configuration.swift */; }; DB336F43278EB1690031E64B /* MediaView+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB336F42278EB1680031E64B /* MediaView+Configuration.swift */; }; - DB35FC1F2612F1D9006193C9 /* ProfileRelationshipActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB35FC1E2612F1D9006193C9 /* ProfileRelationshipActionButton.swift */; }; DB36679D268AB91B0027D07F /* ComposeStatusAttachmentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB36679C268AB91B0027D07F /* ComposeStatusAttachmentTableViewCell.swift */; }; DB36679F268ABAF20027D07F /* ComposeStatusAttachmentSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB36679E268ABAF20027D07F /* ComposeStatusAttachmentSection.swift */; }; DB3667A1268ABB2E0027D07F /* ComposeStatusAttachmentItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A0268ABB2E0027D07F /* ComposeStatusAttachmentItem.swift */; }; @@ -232,6 +231,9 @@ DB3E6FEF2806D82600B035AE /* DiscoveryNewsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FEE2806D82600B035AE /* DiscoveryNewsViewModel.swift */; }; DB3E6FF12806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF02806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift */; }; DB3E6FF32806D97400B035AE /* DiscoveryNewsViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF22806D97400B035AE /* DiscoveryNewsViewModel+State.swift */; }; + DB3E6FF52807C40300B035AE /* DiscoveryForYouViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF42807C40300B035AE /* DiscoveryForYouViewController.swift */; }; + DB3E6FF82807C45300B035AE /* DiscoveryForYouViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF72807C45300B035AE /* DiscoveryForYouViewModel.swift */; }; + DB3E6FFA2807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF92807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift */; }; DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD525BAA00100D1B89D /* AppDelegate.swift */; }; DB427DD825BAA00100D1B89D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD725BAA00100D1B89D /* SceneDelegate.swift */; }; DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DB427DDB25BAA00100D1B89D /* Main.storyboard */; }; @@ -370,7 +372,6 @@ DB6B7500272FF73800C70B6E /* UserTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B74FF272FF73800C70B6E /* UserTableViewCell.swift */; }; DB6B750427300B4000C70B6E /* TimelineFooterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B750327300B4000C70B6E /* TimelineFooterTableViewCell.swift */; }; DB6C8C0F25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */; }; - DB6D1B3D2636857500ACB481 /* AppearancePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */; }; DB6D1B44263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D1B43263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift */; }; DB6D9F3526351B7A008423CD /* NotificationService+Decrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D9F3426351B7A008423CD /* NotificationService+Decrypt.swift */; }; DB6D9F42263527CE008423CD /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB6D9F41263527CE008423CD /* AlamofireImage */; }; @@ -502,8 +503,6 @@ DBB525562611EDCA002F1F29 /* UserTimelineViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB525552611EDCA002F1F29 /* UserTimelineViewModel.swift */; }; DBB5255E2611F07A002F1F29 /* ProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB5255D2611F07A002F1F29 /* ProfileViewModel.swift */; }; DBB525642612C988002F1F29 /* MeProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB525632612C988002F1F29 /* MeProfileViewModel.swift */; }; - DBB5256E2612D5A1002F1F29 /* ProfileStatusDashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB5256D2612D5A1002F1F29 /* ProfileStatusDashboardView.swift */; }; - DBB525852612D6DD002F1F29 /* ProfileStatusDashboardMeterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB525842612D6DD002F1F29 /* ProfileStatusDashboardMeterView.swift */; }; DBB8AB4626AECDE200F6D281 /* SendPostIntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB8AB4526AECDE200F6D281 /* SendPostIntentHandler.swift */; }; DBB8AB4826AED09C00F6D281 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DBB8AB4726AED09C00F6D281 /* MastodonSDK */; }; DBB8AB4A26AED0B500F6D281 /* APIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB8AB4926AED0B500F6D281 /* APIService.swift */; }; @@ -518,7 +517,6 @@ DBBC24CB26A546C000398BB9 /* ThemePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */; }; DBBC24D126A5484F00398BB9 /* UITextView+Placeholder in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24D026A5484F00398BB9 /* UITextView+Placeholder */; }; DBBC24DC26A54BCB00398BB9 /* MastodonRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */; }; - DBBC24DE26A54BCB00398BB9 /* MastodonMetricFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */; }; DBBE1B4525F3474B0081417A /* MastodonPickServerAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBE1B4425F3474B0081417A /* MastodonPickServerAppearance.swift */; }; DBBF1DBF2652401B00E5B703 /* AutoCompleteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBF1DBE2652401B00E5B703 /* AutoCompleteViewModel.swift */; }; DBBF1DC226524D2900E5B703 /* AutoCompleteTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBF1DC126524D2900E5B703 /* AutoCompleteTableViewCell.swift */; }; @@ -594,7 +592,6 @@ DBFEF05F26A57715006D7ED1 /* StatusAuthorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEF05926A576EE006D7ED1 /* StatusAuthorView.swift */; }; DBFEF06026A57715006D7ED1 /* StatusAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEF05A26A576EE006D7ED1 /* StatusAttachmentView.swift */; }; DBFEF06326A577F2006D7ED1 /* StatusAttachmentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEF06226A577F2006D7ED1 /* StatusAttachmentViewModel.swift */; }; - DBFEF06926A67E45006D7ED1 /* AppearancePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */; }; DBFEF06D26A67FB7006D7ED1 /* StatusAttachmentViewModel+UploadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEF06C26A67FB7006D7ED1 /* StatusAttachmentViewModel+UploadState.swift */; }; DBFEF06F26A690C4006D7ED1 /* APIService+APIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98337E25C9452D00AD9700 /* APIService+APIError.swift */; }; DBFEF07326A6913D006D7ED1 /* APIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEF07226A6913D006D7ED1 /* APIService.swift */; }; @@ -945,7 +942,6 @@ DB336F3E278E668C0031E64B /* StatusTableViewCell+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusTableViewCell+ViewModel.swift"; sourceTree = ""; }; DB336F40278E68480031E64B /* StatusView+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusView+Configuration.swift"; sourceTree = ""; }; DB336F42278EB1680031E64B /* MediaView+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MediaView+Configuration.swift"; sourceTree = ""; }; - DB35FC1E2612F1D9006193C9 /* ProfileRelationshipActionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileRelationshipActionButton.swift; sourceTree = ""; }; DB36679C268AB91B0027D07F /* ComposeStatusAttachmentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusAttachmentTableViewCell.swift; sourceTree = ""; }; DB36679E268ABAF20027D07F /* ComposeStatusAttachmentSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusAttachmentSection.swift; sourceTree = ""; }; DB3667A0268ABB2E0027D07F /* ComposeStatusAttachmentItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusAttachmentItem.swift; sourceTree = ""; }; @@ -963,6 +959,9 @@ DB3E6FEE2806D82600B035AE /* DiscoveryNewsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryNewsViewModel.swift; sourceTree = ""; }; DB3E6FF02806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryNewsViewModel+Diffable.swift"; sourceTree = ""; }; DB3E6FF22806D97400B035AE /* DiscoveryNewsViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryNewsViewModel+State.swift"; sourceTree = ""; }; + DB3E6FF42807C40300B035AE /* DiscoveryForYouViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryForYouViewController.swift; sourceTree = ""; }; + DB3E6FF72807C45300B035AE /* DiscoveryForYouViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryForYouViewModel.swift; sourceTree = ""; }; + DB3E6FF92807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryForYouViewModel+Diffable.swift"; sourceTree = ""; }; DB427DD225BAA00100D1B89D /* Mastodon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mastodon.app; sourceTree = BUILT_PRODUCTS_DIR; }; DB427DD525BAA00100D1B89D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DB427DD725BAA00100D1B89D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -1119,7 +1118,6 @@ DB6B74FF272FF73800C70B6E /* UserTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTableViewCell.swift; sourceTree = ""; }; DB6B750327300B4000C70B6E /* TimelineFooterTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineFooterTableViewCell.swift; sourceTree = ""; }; DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Mastodon+Entity+Error.swift"; sourceTree = ""; }; - DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearancePreference.swift; sourceTree = ""; }; DB6D1B43263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Mastodon+API+Subscriptions+Policy.swift"; sourceTree = ""; }; DB6D9F3426351B7A008423CD /* NotificationService+Decrypt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NotificationService+Decrypt.swift"; sourceTree = ""; }; DB6D9F4826353FD6008423CD /* Subscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Subscription.swift; sourceTree = ""; }; @@ -1261,15 +1259,12 @@ DBB525552611EDCA002F1F29 /* UserTimelineViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTimelineViewModel.swift; sourceTree = ""; }; DBB5255D2611F07A002F1F29 /* ProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewModel.swift; sourceTree = ""; }; DBB525632612C988002F1F29 /* MeProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeProfileViewModel.swift; sourceTree = ""; }; - DBB5256D2612D5A1002F1F29 /* ProfileStatusDashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileStatusDashboardView.swift; sourceTree = ""; }; - DBB525842612D6DD002F1F29 /* ProfileStatusDashboardMeterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileStatusDashboardMeterView.swift; sourceTree = ""; }; DBB8AB4526AECDE200F6D281 /* SendPostIntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendPostIntentHandler.swift; sourceTree = ""; }; DBB8AB4926AED0B500F6D281 /* APIService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIService.swift; sourceTree = ""; }; DBB9759B262462E1004620BD /* ThreadMetaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadMetaView.swift; sourceTree = ""; }; DBBC24A726A52F9000398BB9 /* ComposeToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeToolbarView.swift; sourceTree = ""; }; DBBC24AB26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusContentTableViewCell.swift; sourceTree = ""; }; DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonRegex.swift; sourceTree = ""; }; - DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonMetricFormatter.swift; sourceTree = ""; }; DBBC50C0278ED49200AF0CC6 /* MastodonAuthenticationBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonAuthenticationBox.swift; sourceTree = ""; }; DBBE1B4425F3474B0081417A /* MastodonPickServerAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonPickServerAppearance.swift; sourceTree = ""; }; DBBF1DBE2652401B00E5B703 /* AutoCompleteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteViewModel.swift; sourceTree = ""; }; @@ -2147,6 +2142,16 @@ path = News; sourceTree = ""; }; + DB3E6FF62807C40500B035AE /* ForYou */ = { + isa = PBXGroup; + children = ( + DB3E6FF42807C40300B035AE /* DiscoveryForYouViewController.swift */, + DB3E6FF72807C45300B035AE /* DiscoveryForYouViewModel.swift */, + DB3E6FF92807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift */, + ); + path = ForYou; + sourceTree = ""; + }; DB427DC925BAA00100D1B89D = { isa = PBXGroup; children = ( @@ -2378,7 +2383,6 @@ children = ( DBA465942696E387002B41DB /* AppPreference.swift */, DB647C5826F1EA2700F7F82C /* WizardPreference.swift */, - DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */, DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */, DB1D842F26566512000346B3 /* KeyboardPreference.swift */, DBCBCC0C2680B908000F5B51 /* HomeTimelinePreference.swift */, @@ -3040,9 +3044,6 @@ isa = PBXGroup; children = ( DBB5254F2611ED6D002F1F29 /* ProfileHeaderView.swift */, - DBB5256D2612D5A1002F1F29 /* ProfileStatusDashboardView.swift */, - DBB525842612D6DD002F1F29 /* ProfileStatusDashboardMeterView.swift */, - DB35FC1E2612F1D9006193C9 /* ProfileRelationshipActionButton.swift */, DBF98149265E24F500E4BA07 /* ProfileFieldCollectionViewHeaderFooterView.swift */, ); path = View; @@ -3061,7 +3062,6 @@ children = ( DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */, DBBC50C0278ED49200AF0CC6 /* MastodonAuthenticationBox.swift */, - DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */, DBF3B7402733EB9400E21627 /* MastodonLocalCode.swift */, ); path = Helper; @@ -3113,6 +3113,7 @@ DBDFF19828055A0900557A48 /* Posts */, DB3E6FDE2806A41200B035AE /* Hashtags */, DB3E6FED2806D7FC00B035AE /* News */, + DB3E6FF62807C40500B035AE /* ForYou */, DBDFF19928055A1400557A48 /* DiscoveryViewController.swift */, DBDFF19B28055BD600557A48 /* DiscoveryViewModel.swift */, ); @@ -3947,7 +3948,6 @@ DBDFF1952805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift in Sources */, DB03A795272A981400EE37C5 /* ContentSplitViewController.swift in Sources */, DBDFF19C28055BD600557A48 /* DiscoveryViewModel.swift in Sources */, - DBBC24DE26A54BCB00398BB9 /* MastodonMetricFormatter.swift in Sources */, DB06180A2785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift in Sources */, DBB45B6227B51112002DC5A7 /* SuggestionAccountViewModel+Diffable.swift in Sources */, DBB3BA2A26A81C020004F2D4 /* FLAnimatedImageView.swift in Sources */, @@ -3974,7 +3974,6 @@ DBE3CE07261D6A0E00430CC6 /* FavoriteViewModel+Diffable.swift in Sources */, 2D34D9DB261494120081BFC0 /* APIService+Search.swift in Sources */, 5B90C48B26259C120002E742 /* APIService+CoreData+Subscriptions.swift in Sources */, - DBB5256E2612D5A1002F1F29 /* ProfileStatusDashboardView.swift in Sources */, DBA9443E265CFA6400C537E1 /* ProfileFieldCollectionViewCell.swift in Sources */, DB025B93278D6501002F581E /* Persistence.swift in Sources */, 2D24E1232626ED9D00A59D4F /* UIView+Gesture.swift in Sources */, @@ -4066,11 +4065,11 @@ DB697DD4278F4927004EF2F7 /* StatusTableViewCellDelegate.swift in Sources */, DB0FCB902796C5EB006C02E2 /* APIService+Trend.swift in Sources */, DBA5E7A5263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift in Sources */, + DB3E6FF52807C40300B035AE /* DiscoveryForYouViewController.swift in Sources */, DB9D7C21269824B80054B3DF /* APIService+Filter.swift in Sources */, 2D38F1E525CD46C100561493 /* HomeTimelineViewModel.swift in Sources */, DB0FCB842796B2A2006C02E2 /* FavoriteViewController+DataSourceProvider.swift in Sources */, DBCC3B36261440BA0045B23D /* UINavigationController.swift in Sources */, - DBB525852612D6DD002F1F29 /* ProfileStatusDashboardMeterView.swift in Sources */, DB0FCB68279507EF006C02E2 /* DataSourceFacade+Meta.swift in Sources */, DB63F75C279956D000455B82 /* Persistence+Tag.swift in Sources */, 2D84350525FF858100EECE90 /* UIScrollView.swift in Sources */, @@ -4112,7 +4111,6 @@ DBBF1DCB2652539E00E5B703 /* AutoCompleteItem.swift in Sources */, DB84811727883C2600BBEABA /* MastodonRegisterPasswordHintTableViewCell.swift in Sources */, 2DA6054725F716A2006356F9 /* PlaybackState.swift in Sources */, - DB35FC1F2612F1D9006193C9 /* ProfileRelationshipActionButton.swift in Sources */, DB98EB6727B216560082E365 /* ReportResultViewModel+Diffable.swift in Sources */, DBC7A672260C897100E57475 /* StatusContentWarningEditorView.swift in Sources */, DB025B95278D6530002F581E /* Persistence+MastodonUser.swift in Sources */, @@ -4178,6 +4176,7 @@ DB852D1C26FB021500FC9D81 /* RootSplitViewController.swift in Sources */, DB697DD1278F4871004EF2F7 /* AutoGenerateTableViewDelegate.swift in Sources */, DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */, + DB3E6FFA2807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift in Sources */, DB1FD44425F26CCC004CFCFC /* PickServerSection.swift in Sources */, DBB45B6027B50A4F002DC5A7 /* RecommendAccountItem.swift in Sources */, 0FB3D30F25E525CD00AAD544 /* PickServerCategoryView.swift in Sources */, @@ -4311,6 +4310,7 @@ DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */, 2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */, DB3E6FF12806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift in Sources */, + DB3E6FF82807C45300B035AE /* DiscoveryForYouViewModel.swift in Sources */, DB49A62525FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift in Sources */, DB4924E226312AB200E9DB22 /* NotificationService.swift in Sources */, DB6D9F6F2635807F008423CD /* Setting.swift in Sources */, @@ -4327,7 +4327,6 @@ DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */, DB63F74B279914A000455B82 /* FollowingListViewController+DataSourceProvider.swift in Sources */, DBB525362611ECEB002F1F29 /* UserTimelineViewController.swift in Sources */, - DB6D1B3D2636857500ACB481 /* AppearancePreference.swift in Sources */, DB938F3326243D6200E5B6C1 /* TimelineTopLoaderTableViewCell.swift in Sources */, DB98EB4927B0F0CD0082E365 /* ReportStatusTableViewCell.swift in Sources */, DB3667A4268AE2370027D07F /* ComposeStatusPollTableViewCell.swift in Sources */, @@ -4424,7 +4423,6 @@ DBBC24A826A52F9000398BB9 /* ComposeToolbarView.swift in Sources */, DBFEF05B26A57715006D7ED1 /* ComposeViewModel.swift in Sources */, DBFEF06326A577F2006D7ED1 /* StatusAttachmentViewModel.swift in Sources */, - DBFEF06926A67E45006D7ED1 /* AppearancePreference.swift in Sources */, DBC6461526A170AB00B0E31B /* ShareViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 55845d58..1444a8b2 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 23 + 22 MastodonIntents.xcscheme_^#shared#^_ @@ -124,7 +124,7 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 22 + 23 ShareActionExtension.xcscheme_^#shared#^_ diff --git a/Mastodon/Diffiable/Discovery/DiscoveryItem.swift b/Mastodon/Diffiable/Discovery/DiscoveryItem.swift index 181756d2..024c4a2d 100644 --- a/Mastodon/Diffiable/Discovery/DiscoveryItem.swift +++ b/Mastodon/Diffiable/Discovery/DiscoveryItem.swift @@ -7,9 +7,11 @@ import Foundation import MastodonSDK +import CoreDataStack enum DiscoveryItem: Hashable { case hashtag(Mastodon.Entity.Tag) case link(Mastodon.Entity.Link) + case user(ManagedObjectRecord) case bottomLoader } diff --git a/Mastodon/Diffiable/Discovery/DiscoverySection.swift b/Mastodon/Diffiable/Discovery/DiscoverySection.swift index 32683609..f0c358a1 100644 --- a/Mastodon/Diffiable/Discovery/DiscoverySection.swift +++ b/Mastodon/Diffiable/Discovery/DiscoverySection.swift @@ -29,8 +29,9 @@ extension DiscoverySection { ) -> UITableViewDiffableDataSource { tableView.register(TrendTableViewCell.self, forCellReuseIdentifier: String(describing: TrendTableViewCell.self)) tableView.register(NewsTableViewCell.self, forCellReuseIdentifier: String(describing: NewsTableViewCell.self)) + tableView.register(ProfileCardTableViewCell.self, forCellReuseIdentifier: String(describing: ProfileCardTableViewCell.self)) tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self)) - + return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item in switch item { case .hashtag(let tag): @@ -41,6 +42,17 @@ extension DiscoverySection { let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: NewsTableViewCell.self), for: indexPath) as! NewsTableViewCell cell.newsView.configure(link: link) return cell + case .user(let record): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ProfileCardTableViewCell.self), for: indexPath) as! ProfileCardTableViewCell + context.managedObjectContext.performAndWait { + guard let user = record.object(in: context.managedObjectContext) else { return } + cell.profileCardView.configure(user: user) + } + context.authenticationService.activeMastodonAuthentication + .map { $0?.user } + .assign(to: \.me, on: cell.profileCardView.viewModel.relationshipViewModel) + .store(in: &cell.disposeBag) + return cell case .bottomLoader: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell cell.activityIndicatorView.startAnimating() diff --git a/Mastodon/Extension/CoreDataStack/MastodonUser.swift b/Mastodon/Extension/CoreDataStack/MastodonUser.swift index 02a98368..bc5f159d 100644 --- a/Mastodon/Extension/CoreDataStack/MastodonUser.swift +++ b/Mastodon/Extension/CoreDataStack/MastodonUser.swift @@ -9,53 +9,6 @@ import Foundation import CoreDataStack import MastodonSDK -extension MastodonUser { - - public var displayNameWithFallback: String { - return !displayName.isEmpty ? displayName : username - } - - public var acctWithDomain: String { - if !acct.contains("@") { - // Safe concat due to username cannot contains "@" - return username + "@" + domain - } else { - return acct - } - } - - public var domainFromAcct: String { - if !acct.contains("@") { - return domain - } else { - let domain = acct.split(separator: "@").last - return String(domain!) - } - } - -} - -extension MastodonUser { - - public func headerImageURL() -> URL? { - return URL(string: header) - } - - public func headerImageURLWithFallback(domain: String) -> URL { - return URL(string: header) ?? URL(string: "https://\(domain)/headers/original/missing.png")! - } - - public func avatarImageURL() -> URL? { - let string = UserDefaults.shared.preferredStaticAvatar ? avatarStatic ?? avatar : avatar - return URL(string: string) - } - - public func avatarImageURLWithFallback(domain: String) -> URL { - return avatarImageURL() ?? URL(string: "https://\(domain)/avatars/original/missing.png")! - } - -} - extension MastodonUser { public var profileURL: URL { diff --git a/Mastodon/Persistence/Extension/MastodonEmoji.swift b/Mastodon/Persistence/Extension/MastodonEmoji.swift index e9274a24..2ea23c67 100644 --- a/Mastodon/Persistence/Extension/MastodonEmoji.swift +++ b/Mastodon/Persistence/Extension/MastodonEmoji.swift @@ -22,13 +22,3 @@ extension MastodonEmoji { ) } } - -extension Collection where Element == MastodonEmoji { - public var asDictionary: MastodonContent.Emojis { - var dictionary: MastodonContent.Emojis = [:] - for emoji in self { - dictionary[emoji.code] = emoji.url - } - return dictionary - } -} diff --git a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift index acb92b5f..187d7311 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift @@ -16,6 +16,7 @@ final class DiscoveryViewModel { let discoveryPostsViewController: DiscoveryPostsViewController let discoveryHashtagsViewController: DiscoveryHashtagsViewController let discoveryNewsViewController: DiscoveryNewsViewController + let discoveryForYouViewController: DiscoveryForYouViewController // output let barItems: [TMBarItemable] = { @@ -33,6 +34,7 @@ final class DiscoveryViewModel { discoveryPostsViewController, discoveryHashtagsViewController, discoveryNewsViewController, + discoveryForYouViewController, ] } @@ -61,6 +63,12 @@ final class DiscoveryViewModel { viewController.viewModel = DiscoveryNewsViewModel(context: context) return viewController }() + discoveryForYouViewController = { + let viewController = DiscoveryForYouViewController() + setupDependency(viewController) + viewController.viewModel = DiscoveryForYouViewModel(context: context) + return viewController + }() // end init } diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift new file mode 100644 index 00000000..4654769d --- /dev/null +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift @@ -0,0 +1,127 @@ +// +// DiscoveryForYouViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-4-14. +// + +import os.log +import UIKit +import Combine +import MastodonUI + +final class DiscoveryForYouViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + + let logger = Logger(subsystem: "DiscoveryForYouViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var viewModel: DiscoveryForYouViewModel! + + let mediaPreviewTransitionController = MediaPreviewTransitionController() + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 100 + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + return tableView + }() + + let refreshControl = UIRefreshControl() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension DiscoveryForYouViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.view.backgroundColor = theme.secondarySystemBackgroundColor + } + .store(in: &disposeBag) + + tableView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(tableView) + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + tableView.delegate = self + viewModel.setupDiffableDataSource( + tableView: tableView + ) + + tableView.refreshControl = refreshControl + refreshControl.addTarget(self, action: #selector(DiscoveryForYouViewController.refreshControlValueChanged(_:)), for: .valueChanged) + viewModel.$isFetching + .receive(on: DispatchQueue.main) + .sink { [weak self] isFetching in + guard let self = self else { return } + if !isFetching { + self.refreshControl.endRefreshing() + } + } + .store(in: &disposeBag) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + refreshControl.endRefreshing() + tableView.deselectRow(with: transitionCoordinator, animated: animated) + } + +} + +extension DiscoveryForYouViewController { + + @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { + Task { + try await viewModel.fetch() + } + } + +} + +// MARK: - UITableViewDelegate +extension DiscoveryForYouViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(indexPath)") + guard case let .user(record) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return } + guard let user = record.object(in: context.managedObjectContext) else { return } + let profileViewModel = CachedProfileViewModel( + context: context, + mastodonUser: user + ) + coordinator.present( + scene: .profile(viewModel: profileViewModel), + from: self, + transition: .show + ) + } + +} + +// MARK: ScrollViewContainer +extension DiscoveryForYouViewController: ScrollViewContainer { + var scrollView: UIScrollView? { + tableView + } +} diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift new file mode 100644 index 00000000..23114073 --- /dev/null +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift @@ -0,0 +1,43 @@ +// +// DiscoveryForYouViewModel+Diffable.swift +// Mastodon +// +// Created by MainasuK on 2022-4-14. +// + +import UIKit +import Combine + +extension DiscoveryForYouViewModel { + + func setupDiffableDataSource( + tableView: UITableView + ) { + diffableDataSource = DiscoverySection.diffableDataSource( + tableView: tableView, + context: context, + configuration: DiscoverySection.Configuration() + ) + + Task { + try await fetch() + } + + userFetchedResultsController.$records + .receive(on: DispatchQueue.main) + .sink { [weak self] records in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.forYou]) + + let items = records.map { DiscoveryItem.user($0) } + snapshot.appendItems(items, toSection: .forYou) + + diffableDataSource.applySnapshot(snapshot, animated: false) + } + .store(in: &disposeBag) + } + +} diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift new file mode 100644 index 00000000..7be4aeba --- /dev/null +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift @@ -0,0 +1,75 @@ +// +// DiscoveryForYouViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-14. +// + +import os.log +import UIKit +import Combine +import GameplayKit +import CoreData +import CoreDataStack +import MastodonSDK + +final class DiscoveryForYouViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + let userFetchedResultsController: UserFetchedResultsController + @Published var isFetching = false + + // output + var diffableDataSource: UITableViewDiffableDataSource? + let didLoadLatest = PassthroughSubject() + + init(context: AppContext) { + self.context = context + self.userFetchedResultsController = UserFetchedResultsController( + managedObjectContext: context.managedObjectContext, + domain: nil, + additionalPredicate: nil + ) + // end init + + context.authenticationService.activeMastodonAuthenticationBox + .map { $0?.domain } + .assign(to: \.domain, on: userFetchedResultsController) + .store(in: &disposeBag) + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension DiscoveryForYouViewModel { + func fetch() async throws { + guard !isFetching else { return } + isFetching = true + defer { isFetching = false } + + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } + + do { + let response = try await context.apiService.suggestionAccountV2( + query: nil, + authenticationBox: authenticationBox + ) + let userIDs = response.value.map { $0.account.id } + userFetchedResultsController.userIDs = userIDs + } catch { + // fallback V1 + let response2 = try await context.apiService.suggestionAccount( + query: nil, + authenticationBox: authenticationBox + ) + let userIDs = response2.value.map { $0.id } + userFetchedResultsController.userIDs = userIDs + } + } +} diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift index 82d604d6..37d93e5b 100644 --- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift @@ -70,8 +70,6 @@ extension DiscoveryNewsViewModel.State { super.didEnter(from: previousState) guard let viewModel = viewModel, let stateMachine = stateMachine else { return } - viewModel.links = [] - stateMachine.enter(Loading.self) } } @@ -113,7 +111,6 @@ extension DiscoveryNewsViewModel.State { class Loading: DiscoveryNewsViewModel.State { var offset: Int? - var isReloading: Bool { return offset == nil } override func isValidNextState(_ stateClass: AnyClass) -> Bool { switch stateClass { @@ -146,6 +143,7 @@ extension DiscoveryNewsViewModel.State { } let offset = self.offset + let isReloading = offset == nil Task { do { @@ -169,7 +167,7 @@ extension DiscoveryNewsViewModel.State { self.offset = newOffset var hasNewItemsAppend = false - var links = viewModel.links + var links = isReloading ? [] : viewModel.links for link in response.value { guard !links.contains(link) else { continue } links.append(link) diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift index 199215d1..a8e2e7c2 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift @@ -68,10 +68,7 @@ extension DiscoveryPostsViewModel.State { override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - guard let viewModel = viewModel, let stateMachine = stateMachine else { return } - - // reset - viewModel.statusFetchedResultsController.statusIDs.value = [] + guard let _ = viewModel, let stateMachine = stateMachine else { return } stateMachine.enter(Loading.self) } @@ -145,6 +142,7 @@ extension DiscoveryPostsViewModel.State { } let offset = self.offset + let isReloading = offset == nil Task { do { @@ -168,7 +166,7 @@ extension DiscoveryPostsViewModel.State { self.offset = newOffset var hasNewStatusesAppend = false - var statusIDs = viewModel.statusFetchedResultsController.statusIDs.value + var statusIDs = isReloading ? [] : viewModel.statusFetchedResultsController.statusIDs.value for status in response.value { guard !statusIDs.contains(status.id) else { continue } statusIDs.append(status.id) diff --git a/Mastodon/Scene/Profile/ProfileViewModel.swift b/Mastodon/Scene/Profile/ProfileViewModel.swift index 403437da..ac8c12e9 100644 --- a/Mastodon/Scene/Profile/ProfileViewModel.swift +++ b/Mastodon/Scene/Profile/ProfileViewModel.swift @@ -13,10 +13,11 @@ import MastodonSDK import MastodonMeta import MastodonAsset import MastodonLocalization +import MastodonUI // please override this base class class ProfileViewModel: NSObject { - + let logger = Logger(subsystem: "ProfileViewModel", category: "ViewModel") typealias UserID = String @@ -372,101 +373,6 @@ extension ProfileViewModel { } -extension ProfileViewModel { - - enum RelationshipAction: Int, CaseIterable { - case none // set hide from UI - case follow - case request - case pending - case following - case muting - case blocked - case blocking - case suspended - case edit - case editing - case updating - - var option: RelationshipActionOptionSet { - return RelationshipActionOptionSet(rawValue: 1 << rawValue) - } - } - - // construct option set on the enum for safe iterator - struct RelationshipActionOptionSet: OptionSet { - let rawValue: Int - - static let none = RelationshipAction.none.option - static let follow = RelationshipAction.follow.option - static let request = RelationshipAction.request.option - static let pending = RelationshipAction.pending.option - static let following = RelationshipAction.following.option - static let muting = RelationshipAction.muting.option - static let blocked = RelationshipAction.blocked.option - static let blocking = RelationshipAction.blocking.option - static let suspended = RelationshipAction.suspended.option - static let edit = RelationshipAction.edit.option - static let editing = RelationshipAction.editing.option - static let updating = RelationshipAction.updating.option - - static let editOptions: RelationshipActionOptionSet = [.edit, .editing, .updating] - - func highPriorityAction(except: RelationshipActionOptionSet) -> RelationshipAction? { - let set = subtracting(except) - for action in RelationshipAction.allCases.reversed() where set.contains(action.option) { - return action - } - - return nil - } - - var title: String { - guard let highPriorityAction = self.highPriorityAction(except: []) else { - assertionFailure() - return " " - } - switch highPriorityAction { - case .none: return " " - case .follow: return L10n.Common.Controls.Friendship.follow - case .request: return L10n.Common.Controls.Friendship.request - case .pending: return L10n.Common.Controls.Friendship.pending - case .following: return L10n.Common.Controls.Friendship.following - case .muting: return L10n.Common.Controls.Friendship.muted - case .blocked: return L10n.Common.Controls.Friendship.follow // blocked by user - case .blocking: return L10n.Common.Controls.Friendship.blocked - case .suspended: return L10n.Common.Controls.Friendship.follow - case .edit: return L10n.Common.Controls.Friendship.editInfo - case .editing: return L10n.Common.Controls.Actions.done - case .updating: return " " - } - } - - @available(*, deprecated, message: "") - var backgroundColor: UIColor { - guard let highPriorityAction = self.highPriorityAction(except: []) else { - assertionFailure() - return Asset.Colors.brandBlue.color - } - switch highPriorityAction { - case .none: return Asset.Colors.brandBlue.color - case .follow: return Asset.Colors.brandBlue.color - case .request: return Asset.Colors.brandBlue.color - case .pending: return Asset.Colors.brandBlue.color - case .following: return Asset.Colors.brandBlue.color - case .muting: return Asset.Colors.alertYellow.color - case .blocked: return Asset.Colors.brandBlue.color - case .blocking: return Asset.Colors.danger.color - case .suspended: return Asset.Colors.brandBlue.color - case .edit: return Asset.Colors.brandBlue.color - case .editing: return Asset.Colors.brandBlue.color - case .updating: return Asset.Colors.brandBlue.color - } - } - - } -} - extension ProfileViewModel { func updateProfileInfo( headerProfileInfo: ProfileHeaderViewModel.ProfileInfo, diff --git a/Mastodon/Service/APIService/APIService+Recommend.swift b/Mastodon/Service/APIService/APIService+Recommend.swift index cb195b60..6e457ad0 100644 --- a/Mastodon/Service/APIService/APIService+Recommend.swift +++ b/Mastodon/Service/APIService/APIService+Recommend.swift @@ -13,12 +13,13 @@ import CoreDataStack import OSLog extension APIService { + func suggestionAccount( query: Mastodon.API.Suggestions.Query?, authenticationBox: MastodonAuthenticationBox ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Account]> { - let response = try await Mastodon.API.Suggestions.get( + let response = try await Mastodon.API.Suggestions.accounts( session: session, domain: authenticationBox.domain, query: query, @@ -47,7 +48,7 @@ extension APIService { query: Mastodon.API.Suggestions.Query?, authenticationBox: MastodonAuthenticationBox ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.V2.SuggestionAccount]> { - let response = try await Mastodon.API.V2.Suggestions.get( + let response = try await Mastodon.API.V2.Suggestions.accounts( session: session, domain: authenticationBox.domain, query: query, diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index d6078090..dd562f14 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -94,6 +94,7 @@ let package = Package( .product(name: "Alamofire", package: "Alamofire"), .product(name: "AlamofireImage", package: "AlamofireImage"), .product(name: "MetaTextKit", package: "MetaTextKit"), + .product(name: "MastodonMeta", package: "MetaTextKit"), .product(name: "FLAnimatedImage", package: "FLAnimatedImage"), ] ), diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/Contents.json new file mode 100644 index 00000000..6e965652 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "provides-namespace" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/profile.card.background.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/profile.card.background.colorset/Contents.json new file mode 100644 index 00000000..1fc21a87 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/profile.card.background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "251", + "green" : "250", + "red" : "249" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "4", + "green" : "5", + "red" : "6" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift index 26e54900..3e7fa5c1 100644 --- a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift +++ b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift @@ -103,6 +103,9 @@ public enum Asset { public static let star = ImageAsset(name: "ObjectsAndTools/star") } public enum Scene { + public enum Discovery { + public static let profileCardBackground = ColorAsset(name: "Scene/Discovery/profile.card.background") + } public enum Onboarding { public static let avatarPlaceholder = ImageAsset(name: "Scene/Onboarding/avatar.placeholder") public static let background = ColorAsset(name: "Scene/Onboarding/background") diff --git a/Mastodon/Preference/AppearancePreference.swift b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Appearance.swift similarity index 81% rename from Mastodon/Preference/AppearancePreference.swift rename to MastodonSDK/Sources/MastodonCommon/Preference/Preference+Appearance.swift index 034bf965..713c926b 100644 --- a/Mastodon/Preference/AppearancePreference.swift +++ b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Appearance.swift @@ -9,7 +9,7 @@ import UIKit extension UserDefaults { - @objc dynamic var customUserInterfaceStyle: UIUserInterfaceStyle { + @objc public dynamic var customUserInterfaceStyle: UIUserInterfaceStyle { get { register(defaults: [#function: UIUserInterfaceStyle.unspecified.rawValue]) return UIUserInterfaceStyle(rawValue: integer(forKey: #function)) ?? .unspecified @@ -17,7 +17,7 @@ extension UserDefaults { set { self[#function] = newValue.rawValue } } - @objc dynamic var preferredStaticAvatar: Bool { + @objc public dynamic var preferredStaticAvatar: Bool { get { // default false // without set register to profile timeline performance @@ -26,7 +26,7 @@ extension UserDefaults { set { self[#function] = newValue } } - @objc dynamic var preferredStaticEmoji: Bool { + @objc public dynamic var preferredStaticEmoji: Bool { get { // default false // without set register to profile timeline performance diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Suggestions.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Suggestions.swift index 55808964..4c424f3b 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Suggestions.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Suggestions.swift @@ -27,7 +27,7 @@ extension Mastodon.API.Suggestions { /// - query: query /// - authorization: User token. /// - Returns: `AnyPublisher` contains `Accounts` nested in the response - public static func get( + public static func accounts( session: URLSession, domain: String, query: Mastodon.API.Suggestions.Query?, diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+V2+Suggestions.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+V2+Suggestions.swift index 9e6876b4..ed680dba 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+V2+Suggestions.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+V2+Suggestions.swift @@ -20,7 +20,7 @@ extension Mastodon.API.V2.Suggestions { /// - query: query /// - authorization: User token. /// - Returns: `AnyPublisher` contains `AccountsSuggestion` nested in the response - public static func get( + public static func accounts( session: URLSession, domain: String, query: Mastodon.API.Suggestions.Query?, diff --git a/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonEmoji.swift b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonEmoji.swift new file mode 100644 index 00000000..4f097759 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonEmoji.swift @@ -0,0 +1,20 @@ +// +// MastodonEmoji.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import Foundation +import CoreDataStack +import MastodonMeta + +extension Collection where Element == MastodonEmoji { + public var asDictionary: MastodonContent.Emojis { + var dictionary: MastodonContent.Emojis = [:] + for emoji in self { + dictionary[emoji.code] = emoji.url + } + return dictionary + } +} diff --git a/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonUser.swift b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonUser.swift new file mode 100644 index 00000000..9b61ab5f --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonUser.swift @@ -0,0 +1,57 @@ +// +// MastodonUser.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import Foundation +import CoreDataStack +import MastodonCommon + +extension MastodonUser { + + public var displayNameWithFallback: String { + return !displayName.isEmpty ? displayName : username + } + + public var acctWithDomain: String { + if !acct.contains("@") { + // Safe concat due to username cannot contains "@" + return username + "@" + domain + } else { + return acct + } + } + + public var domainFromAcct: String { + if !acct.contains("@") { + return domain + } else { + let domain = acct.split(separator: "@").last + return String(domain!) + } + } + +} + +extension MastodonUser { + + public func headerImageURL() -> URL? { + return URL(string: header) + } + + public func headerImageURLWithFallback(domain: String) -> URL { + return URL(string: header) ?? URL(string: "https://\(domain)/headers/original/missing.png")! + } + + public func avatarImageURL() -> URL? { + let string = UserDefaults.shared.preferredStaticAvatar ? avatarStatic ?? avatar : avatar + return URL(string: string) + } + + public func avatarImageURLWithFallback(domain: String) -> URL { + return avatarImageURL() ?? URL(string: "https://\(domain)/avatars/original/missing.png")! + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/Extension/MetaLabel.swift b/MastodonSDK/Sources/MastodonUI/Extension/MetaLabel.swift index 119e9e03..24a4027f 100644 --- a/MastodonSDK/Sources/MastodonUI/Extension/MetaLabel.swift +++ b/MastodonSDK/Sources/MastodonUI/Extension/MetaLabel.swift @@ -20,6 +20,8 @@ extension MetaLabel { case notificationTitle case profileFieldName case profileFieldValue + case profileCardName + case profileCardUsername case recommendAccountName case titleView case settingTableFooter @@ -51,7 +53,7 @@ extension MetaLabel { textColor = Asset.Colors.Label.secondary.color case .statusName: - font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .bold)) + font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold)) textColor = Asset.Colors.Label.primary.color case .statusUsername: @@ -80,6 +82,14 @@ extension MetaLabel { font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) textColor = Asset.Colors.Label.primary.color + case .profileCardName: + font = .systemFont(ofSize: 17, weight: .semibold) + textColor = Asset.Colors.Label.primary.color + + case .profileCardUsername: + font = .systemFont(ofSize: 15, weight: .regular) + textColor = Asset.Colors.Label.secondary.color + case .titleView: font = .systemFont(ofSize: 17, weight: .semibold) textColor = Asset.Colors.Label.primary.color diff --git a/Mastodon/Helper/MastodonMetricFormatter.swift b/MastodonSDK/Sources/MastodonUI/Helper/MastodonMetricFormatter.swift similarity index 95% rename from Mastodon/Helper/MastodonMetricFormatter.swift rename to MastodonSDK/Sources/MastodonUI/Helper/MastodonMetricFormatter.swift index 3c9c4dd7..50fca8cc 100644 --- a/Mastodon/Helper/MastodonMetricFormatter.swift +++ b/MastodonSDK/Sources/MastodonUI/Helper/MastodonMetricFormatter.swift @@ -7,8 +7,8 @@ import Foundation -final public class MastodonMetricFormatter: Formatter { - +public final class MastodonMetricFormatter: Formatter { + public func string(from number: Int) -> String? { let isPositive = number >= 0 let symbol = isPositive ? "" : "-" diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+Configuration.swift new file mode 100644 index 00000000..3964099d --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+Configuration.swift @@ -0,0 +1,88 @@ +// +// ProfileCardView+Configuration.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import Foundation +import Combine +import CoreDataStack +import Meta +import MastodonMeta + +extension ProfileCardView { + + public func configure(user: MastodonUser) { + // banner + user.publisher(for: \.header) + .map { URL(string: $0) } + .assign(to: \.authorBannerImageURL, on: viewModel) + .store(in: &disposeBag) + // author avatar + Publishers.CombineLatest3( + user.publisher(for: \.avatar), + user.publisher(for: \.avatarStatic), + UserDefaults.shared.publisher(for: \.preferredStaticAvatar) + ) + .map { _ in user.avatarImageURL() } + .assign(to: \.authorAvatarImageURL, on: viewModel) + .store(in: &disposeBag) + // name + Publishers.CombineLatest( + user.publisher(for: \.displayName), + user.publisher(for: \.emojis) + ) + .map { _, emojis in + do { + let content = MastodonContent(content: user.displayNameWithFallback, emojis: emojis.asDictionary) + let metaContent = try MastodonMetaContent.convert(document: content) + return metaContent + } catch { + assertionFailure(error.localizedDescription) + return PlaintextMetaContent(string: user.displayNameWithFallback) + } + } + .assign(to: \.authorName, on: viewModel) + .store(in: &disposeBag) + // username + user.publisher(for: \.acct) + .map { $0 as String? } + .assign(to: \.authorUsername, on: viewModel) + .store(in: &disposeBag) + // bio + Publishers.CombineLatest( + user.publisher(for: \.note), + user.publisher(for: \.emojis) + ) + .map { note, emojis in + guard let note = note else { return nil } + do { + let content = MastodonContent(content: note, emojis: emojis.asDictionary) + let metaContent = try MastodonMetaContent.convert(document: content) + return metaContent + } catch { + assertionFailure(error.localizedDescription) + return nil + } + } + .assign(to: \.bioContent, on: viewModel) + .store(in: &disposeBag) + // relationship + viewModel.relationshipViewModel.user = user + // dashboard + user.publisher(for: \.statusesCount) + .map { Int($0) } + .assign(to: \.statusesCount, on: viewModel) + .store(in: &disposeBag) + user.publisher(for: \.followingCount) + .map { Int($0) } + .assign(to: \.followingCount, on: viewModel) + .store(in: &disposeBag) + user.publisher(for: \.followersCount) + .map { Int($0) } + .assign(to: \.followersCount, on: viewModel) + .store(in: &disposeBag) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift new file mode 100644 index 00000000..0e01161d --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift @@ -0,0 +1,148 @@ +// +// ProfileCardView+ViewModel.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import os.log +import UIKit +import Combine +import Meta +import AlamofireImage +import CoreDataStack +import MastodonLocalization + +extension ProfileCardView { + public class ViewModel: ObservableObject { + let logger = Logger(subsystem: "ProfileCardView", category: "ViewModel") + var disposeBag = Set() + + public let relationshipViewModel = RelationshipViewModel() + + // Author + @Published public var authorBannerImageURL: URL? + @Published public var authorAvatarImageURL: URL? + @Published public var authorName: MetaContent? + @Published public var authorUsername: String? + + @Published public var bioContent: MetaContent? + + @Published public var statusesCount: Int? + @Published public var followingCount: Int? + @Published public var followersCount: Int? + + @Published public var isUpdating = false + @Published public var isFollowedBy = false + @Published public var isMuting = false + @Published public var isBlocking = false + @Published public var isBlockedBy = false + } +} + +extension ProfileCardView.ViewModel { + func bind(view: ProfileCardView) { + bindHeader(view: view) + bindUser(view: view) + bindBio(view: view) + bindRelationship(view: view) + bindDashboard(view: view) + } + + private func bindHeader(view: ProfileCardView) { + $authorBannerImageURL + .sink { url in + guard let url = url else { return } + view.bannerImageView.af.setImage( + withURL: url, + placeholderImage: .placeholder(color: .systemGray3), + imageTransition: .crossDissolve(0.3) + ) + } + .store(in: &disposeBag) + } + + private func bindUser(view: ProfileCardView) { + $authorAvatarImageURL + .sink { url in + view.avatarButton.avatarImageView.configure( + configuration: .init( + url: url, + placeholder: .placeholder(color: .systemGray3) + ) + ) + view.avatarButton.avatarImageView.configure( + cornerConfiguration: .init(corner: .fixed(radius: 12)) + ) + } + .store(in: &disposeBag) + + // name + $authorName + .sink { metaContent in + let metaContent = metaContent ?? PlaintextMetaContent(string: " ") + view.authorNameLabel.configure(content: metaContent) + } + .store(in: &disposeBag) + // username + $authorUsername + .map { text -> String in + guard let text = text else { return "" } + return "@\(text)" + } + .sink { username in + let metaContent = PlaintextMetaContent(string: username) + view.authorUsernameLabel.configure(content: metaContent) + } + .store(in: &disposeBag) + } + + private func bindBio(view: ProfileCardView) { + $bioContent + .sink { metaContent in + let metaContent = metaContent ?? PlaintextMetaContent(string: " ") + view.bioMetaText.configure(content: metaContent) + } + .store(in: &disposeBag) + } + + private func bindRelationship(view: ProfileCardView) { + relationshipViewModel.$optionSet + .receive(on: DispatchQueue.main) + .sink { relationshipActionSet in + let relationshipActionSet = relationshipActionSet ?? .follow + view.relationshipActionButton.configure(actionOptionSet: relationshipActionSet) + } + .store(in: &disposeBag) + } + + private func bindDashboard(view: ProfileCardView) { + $statusesCount + .receive(on: DispatchQueue.main) + .sink { count in + let text = count.flatMap { MastodonMetricFormatter().string(from: $0) } ?? "-" + view.statusDashboardView.postDashboardMeterView.numberLabel.text = text + view.statusDashboardView.postDashboardMeterView.isAccessibilityElement = true + view.statusDashboardView.postDashboardMeterView.accessibilityLabel = L10n.Plural.Count.post(count ?? 0) + } + .store(in: &disposeBag) + $followingCount + .receive(on: DispatchQueue.main) + .sink { count in + let text = count.flatMap { MastodonMetricFormatter().string(from: $0) } ?? "-" + view.statusDashboardView.followingDashboardMeterView.numberLabel.text = text + view.statusDashboardView.followingDashboardMeterView.isAccessibilityElement = true + view.statusDashboardView.followingDashboardMeterView.accessibilityLabel = L10n.Plural.Count.following(count ?? 0) + } + .store(in: &disposeBag) + $followersCount + .receive(on: DispatchQueue.main) + .sink { count in + let text = count.flatMap { MastodonMetricFormatter().string(from: $0) } ?? "-" + view.statusDashboardView.followersDashboardMeterView.numberLabel.text = text + view.statusDashboardView.followersDashboardMeterView.isAccessibilityElement = true + view.statusDashboardView.followersDashboardMeterView.accessibilityLabel = L10n.Plural.Count.follower(count ?? 0) + } + .store(in: &disposeBag) + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift new file mode 100644 index 00000000..a8e90906 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -0,0 +1,235 @@ +// +// ProfileCardView.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import UIKit +import Combine +import MetaTextKit +import MastodonAsset + +public final class ProfileCardView: UIView { + + static let avatarSize = CGSize(width: 56, height: 56) + static let friendshipActionButtonSize = CGSize(width: 108, height: 34) + static let contentMargin: CGFloat = 16 + + private var _disposeBag = Set() + var disposeBag = Set() + + let container = UIStackView() + + let bannerImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFill + imageView.layer.masksToBounds = true + imageView.layer.cornerRadius = 3 + imageView.layer.cornerCurve = .continuous + return imageView + }() + + // avatar + public let avatarButton = AvatarButton() + + // author name + public let authorNameLabel = MetaLabel(style: .profileCardName) + + // author username + public let authorUsernameLabel = MetaLabel(style: .profileCardUsername) + + let bioMetaText: MetaText = { + let metaText = MetaText() + metaText.textView.backgroundColor = .clear + metaText.textView.isEditable = false + metaText.textView.isSelectable = true + metaText.textView.isScrollEnabled = false + //metaText.textView.textContainer.lineFragmentPadding = 0 + //metaText.textView.textContainerInset = .zero + metaText.textView.layer.masksToBounds = false + metaText.textView.textDragInteraction?.isEnabled = false // disable drag for link and attachment + + metaText.textView.layer.masksToBounds = true + metaText.textView.layer.cornerCurve = .continuous + metaText.textView.layer.cornerRadius = 10 + + metaText.paragraphStyle = { + let style = NSMutableParagraphStyle() + style.lineSpacing = 5 + style.paragraphSpacing = 8 + return style + }() + metaText.textAttributes = [ + .font: UIFont.preferredFont(forTextStyle: .body), + .foregroundColor: Asset.Colors.Label.primary.color, + ] + metaText.linkAttributes = [ + .font: UIFont.preferredFont(forTextStyle: .body), + .foregroundColor: Asset.Colors.brandBlue.color, + ] + return metaText + }() + + let statusDashboardView = ProfileStatusDashboardView() + + let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() + let relationshipActionButton: ProfileRelationshipActionButton = { + let button = ProfileRelationshipActionButton() + button.titleLabel?.font = .systemFont(ofSize: 17, weight: .semibold) + button.titleLabel?.adjustsFontSizeToFitWidth = true + button.titleLabel?.minimumScaleFactor = 0.5 + return button + }() + + public private(set) lazy var viewModel: ViewModel = { + let viewModel = ViewModel() + viewModel.bind(view: self) + return viewModel + }() + + public func prepareForReuse() { + disposeBag.removeAll() + bannerImageView.af.cancelImageRequest() + bannerImageView.image = nil + } + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension ProfileCardView { + private func _init() { + avatarButton.isUserInteractionEnabled = false + authorNameLabel.isUserInteractionEnabled = false + authorUsernameLabel.isUserInteractionEnabled = false + bioMetaText.textView.isUserInteractionEnabled = false + statusDashboardView.isUserInteractionEnabled = false + + // container: V - [ bannerContainer | authorContainer | bioMetaText | infoContainer ] + container.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color + container.axis = .vertical + container.spacing = 8 + container.translatesAutoresizingMaskIntoConstraints = false + addSubview(container) + NSLayoutConstraint.activate([ + container.topAnchor.constraint(equalTo: topAnchor), + container.leadingAnchor.constraint(equalTo: leadingAnchor), + container.trailingAnchor.constraint(equalTo: trailingAnchor), + container.bottomAnchor.constraint(equalTo: bottomAnchor), + ]) + + // bannerContainer + let bannerContainer = UIView() + bannerContainer.translatesAutoresizingMaskIntoConstraints = false + container.addArrangedSubview(bannerContainer) + container.setCustomSpacing(6, after: bannerContainer) + + // bannerImageView + bannerImageView.translatesAutoresizingMaskIntoConstraints = false + bannerContainer.addSubview(bannerImageView) + NSLayoutConstraint.activate([ + bannerImageView.topAnchor.constraint(equalTo: bannerContainer.topAnchor, constant: 4), + bannerImageView.leadingAnchor.constraint(equalTo: bannerContainer.leadingAnchor, constant: 4), + bannerContainer.trailingAnchor.constraint(equalTo: bannerImageView.trailingAnchor, constant: 4), + bannerImageView.bottomAnchor.constraint(equalTo: bannerContainer.bottomAnchor), + bannerImageView.widthAnchor.constraint(equalTo: bannerImageView.heightAnchor, multiplier: 335.0/128.0).priority(.required - 1), + ]) + + // authorContainer: H - [ avatarPlaceholder | authorInfoContainer ] + let authorContainer = UIStackView() + authorContainer.axis = .horizontal + authorContainer.spacing = 16 + let authorContainerAdaptiveMarginContainerView = AdaptiveMarginContainerView() + authorContainerAdaptiveMarginContainerView.contentView = authorContainer + authorContainerAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin + container.addArrangedSubview(authorContainerAdaptiveMarginContainerView) + + // avatarPlaceholder + let avatarPlaceholder = UIView() + avatarPlaceholder.translatesAutoresizingMaskIntoConstraints = false + authorContainer.addArrangedSubview(avatarPlaceholder) + NSLayoutConstraint.activate([ + avatarPlaceholder.widthAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.width).priority(.required - 1), + avatarPlaceholder.heightAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.height - 14).priority(.required - 1), + ]) + + avatarButton.translatesAutoresizingMaskIntoConstraints = false + authorContainer.addSubview(avatarButton) + NSLayoutConstraint.activate([ + avatarButton.leadingAnchor.constraint(equalTo: avatarPlaceholder.leadingAnchor), + avatarButton.trailingAnchor.constraint(equalTo: avatarPlaceholder.trailingAnchor), + avatarButton.bottomAnchor.constraint(equalTo: avatarPlaceholder.bottomAnchor), + avatarButton.heightAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.height).priority(.required - 1), + ]) + + let avatarButtonBackgroundView = UIView() + avatarButtonBackgroundView.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color + avatarButtonBackgroundView.layer.masksToBounds = true + avatarButtonBackgroundView.layer.cornerCurve = .continuous + avatarButtonBackgroundView.layer.cornerRadius = 12 + avatarButtonBackgroundView.translatesAutoresizingMaskIntoConstraints = false + authorContainer.insertSubview(avatarButtonBackgroundView, belowSubview: avatarButton) + NSLayoutConstraint.activate([ + avatarButtonBackgroundView.centerXAnchor.constraint(equalTo: avatarButton.centerXAnchor), + avatarButtonBackgroundView.centerYAnchor.constraint(equalTo: avatarButton.centerYAnchor), + avatarButtonBackgroundView.widthAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.width + 4).priority(.required - 1), + avatarButtonBackgroundView.heightAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.height + 4).priority(.required - 1), + ]) + + // authorInfoContainer: V - [ authorNameLabel | authorUsernameLabel ] + let authorInfoContainer = UIStackView() + authorInfoContainer.axis = .vertical + authorInfoContainer.spacing = 2 + authorContainer.addArrangedSubview(authorInfoContainer) + + authorInfoContainer.addArrangedSubview(authorNameLabel) + authorInfoContainer.addArrangedSubview(authorUsernameLabel) + + // bioMetaText + let bioMetaTextAdaptiveMarginContainerView = AdaptiveMarginContainerView() + bioMetaTextAdaptiveMarginContainerView.contentView = bioMetaText.textView + bioMetaTextAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin + container.addArrangedSubview(bioMetaTextAdaptiveMarginContainerView) + container.setCustomSpacing(16, after: bioMetaTextAdaptiveMarginContainerView) + + // infoContainer: H - [ statusDashboardView | (spacer) | relationshipActionButton ] + let infoContainer = UIStackView() + infoContainer.axis = .horizontal + let infoContainerAdaptiveMarginContainerView = AdaptiveMarginContainerView() + infoContainerAdaptiveMarginContainerView.contentView = infoContainer + infoContainerAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin + container.addArrangedSubview(infoContainerAdaptiveMarginContainerView) + infoContainer.addArrangedSubview(statusDashboardView) + infoContainer.addArrangedSubview(UIView()) + let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() + infoContainer.addArrangedSubview(relationshipActionButtonShadowContainer) + + relationshipActionButton.translatesAutoresizingMaskIntoConstraints = false + relationshipActionButtonShadowContainer.addSubview(relationshipActionButton) + NSLayoutConstraint.activate([ + relationshipActionButton.topAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.topAnchor), + relationshipActionButton.leadingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.leadingAnchor), + relationshipActionButton.trailingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.trailingAnchor), + relationshipActionButton.bottomAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.bottomAnchor), + relationshipActionButton.widthAnchor.constraint(greaterThanOrEqualToConstant: ProfileCardView.friendshipActionButtonSize.width).priority(.required - 1), + relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.defaultHigh), + ]) + + let bottomPadding = UIView() + bottomPadding.translatesAutoresizingMaskIntoConstraints = false + container.addArrangedSubview(bottomPadding) + NSLayoutConstraint.activate([ + bottomPadding.heightAnchor.constraint(equalToConstant: 16) + ]) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift index b09fdb44..67cefa47 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift @@ -14,6 +14,7 @@ import MastodonSDK import MastodonAsset import MastodonLocalization import MastodonExtension +import MastodonCommon import CoreDataStack extension StatusView { diff --git a/Mastodon/Scene/Profile/Header/View/ProfileRelationshipActionButton.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileRelationshipActionButton.swift similarity index 80% rename from Mastodon/Scene/Profile/Header/View/ProfileRelationshipActionButton.swift rename to MastodonSDK/Sources/MastodonUI/View/Control/ProfileRelationshipActionButton.swift index 87c189a4..bdf696e7 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileRelationshipActionButton.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileRelationshipActionButton.swift @@ -6,23 +6,23 @@ // import UIKit -import MastodonUI import MastodonAsset +import MastodonLocalization -final class ProfileRelationshipActionButton: RoundedEdgesButton { +public final class ProfileRelationshipActionButton: RoundedEdgesButton { - let activityIndicatorView: UIActivityIndicatorView = { + public let activityIndicatorView: UIActivityIndicatorView = { let activityIndicatorView = UIActivityIndicatorView(style: .medium) activityIndicatorView.color = Asset.Colors.Label.primaryReverse.color return activityIndicatorView }() - override init(frame: CGRect) { + public override init(frame: CGRect) { super.init(frame: frame) _init() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) _init() } @@ -47,7 +47,7 @@ extension ProfileRelationshipActionButton { configureAppearance() } - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) configureAppearance() @@ -55,7 +55,7 @@ extension ProfileRelationshipActionButton { } extension ProfileRelationshipActionButton { - func configure(actionOptionSet: ProfileViewModel.RelationshipActionOptionSet) { + public func configure(actionOptionSet: RelationshipActionOptionSet) { setTitle(actionOptionSet.title, for: .normal) configureAppearance() @@ -87,9 +87,5 @@ extension ProfileRelationshipActionButton { setBackgroundImage(.placeholder(color: Asset.Scene.Profile.RelationshipButton.backgroundHighlightedLight.color), for: .highlighted) setBackgroundImage(.placeholder(color: Asset.Scene.Profile.RelationshipButton.backgroundHighlightedLight.color), for: .disabled) } -// setBackgroundImage(.placeholder(color: actionOptionSet.backgroundColor), for: .normal) -// setBackgroundImage(.placeholder(color: actionOptionSet.backgroundColor.withAlphaComponent(0.5)), for: .highlighted) -// setBackgroundImage(.placeholder(color: actionOptionSet.backgroundColor.withAlphaComponent(0.5)), for: .disabled) } } - diff --git a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardMeterView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardMeterView.swift similarity index 91% rename from Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardMeterView.swift rename to MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardMeterView.swift index 9176d7a3..0c9d243c 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardMeterView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardMeterView.swift @@ -9,9 +9,9 @@ import UIKit import MastodonAsset import MastodonLocalization -final class ProfileStatusDashboardMeterView: UIView { +public final class ProfileStatusDashboardMeterView: UIView { - let numberLabel: UILabel = { + public let numberLabel: UILabel = { let label = UILabel() label.font = { let font = UIFont.systemFont(ofSize: 20, weight: .semibold) @@ -25,7 +25,7 @@ final class ProfileStatusDashboardMeterView: UIView { return label }() - let textLabel: UILabel = { + public let textLabel: UILabel = { let label = UILabel() label.font = .systemFont(ofSize: 13, weight: .regular) label.textColor = Asset.Colors.Label.primary.color @@ -41,12 +41,12 @@ final class ProfileStatusDashboardMeterView: UIView { return label }() - override init(frame: CGRect) { + public override init(frame: CGRect) { super.init(frame: frame) _init() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) _init() } diff --git a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift similarity index 85% rename from Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift rename to MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift index 9448f196..7d8e4fbc 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift @@ -10,24 +10,24 @@ import UIKit import MastodonAsset import MastodonLocalization -protocol ProfileStatusDashboardViewDelegate: AnyObject { +public protocol ProfileStatusDashboardViewDelegate: AnyObject { func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, dashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView, meter: ProfileStatusDashboardView.Meter) } -final class ProfileStatusDashboardView: UIView { +public final class ProfileStatusDashboardView: UIView { - let postDashboardMeterView = ProfileStatusDashboardMeterView() - let followingDashboardMeterView = ProfileStatusDashboardMeterView() - let followersDashboardMeterView = ProfileStatusDashboardMeterView() + public let postDashboardMeterView = ProfileStatusDashboardMeterView() + public let followingDashboardMeterView = ProfileStatusDashboardMeterView() + public let followersDashboardMeterView = ProfileStatusDashboardMeterView() - weak var delegate: ProfileStatusDashboardViewDelegate? + public weak var delegate: ProfileStatusDashboardViewDelegate? - override init(frame: CGRect) { + public override init(frame: CGRect) { super.init(frame: frame) _init() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) _init() } @@ -35,7 +35,7 @@ final class ProfileStatusDashboardView: UIView { } extension ProfileStatusDashboardView { - enum Meter: Hashable { + public enum Meter: Hashable { case post case following case follower @@ -83,7 +83,7 @@ extension ProfileStatusDashboardView { extension ProfileStatusDashboardView { @objc private func tapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) { - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + os_log(.debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) guard let sourceView = sender.view as? ProfileStatusDashboardMeterView else { assertionFailure() return diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift new file mode 100644 index 00000000..a793482a --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift @@ -0,0 +1,68 @@ +// +// ProfileCardTableViewCell.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import UIKit +import Combine + +public final class ProfileCardTableViewCell: UITableViewCell { + + public var disposeBag = Set() + + public let profileCardView: ProfileCardView = { + let profileCardView = ProfileCardView() + profileCardView.layer.masksToBounds = true + profileCardView.layer.cornerRadius = 6 + profileCardView.layer.cornerCurve = .continuous + return profileCardView + }() + + public override func prepareForReuse() { + super.prepareForReuse() + + disposeBag.removeAll() + profileCardView.prepareForReuse() + } + + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + _init() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension ProfileCardTableViewCell { + + private func _init() { + selectionStyle = .none + + let shadowBackgroundContainer = ShadowBackgroundContainer() + shadowBackgroundContainer.cornerRadius = 6 + shadowBackgroundContainer.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(shadowBackgroundContainer) + NSLayoutConstraint.activate([ + shadowBackgroundContainer.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10), + shadowBackgroundContainer.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + shadowBackgroundContainer.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), + contentView.bottomAnchor.constraint(equalTo: shadowBackgroundContainer.bottomAnchor, constant: 10), + ]) + + profileCardView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(profileCardView) + NSLayoutConstraint.activate([ + profileCardView.topAnchor.constraint(equalTo: shadowBackgroundContainer.topAnchor), + profileCardView.leadingAnchor.constraint(equalTo: shadowBackgroundContainer.leadingAnchor), + profileCardView.trailingAnchor.constraint(equalTo: shadowBackgroundContainer.trailingAnchor), + profileCardView.bottomAnchor.constraint(equalTo: shadowBackgroundContainer.bottomAnchor), + ]) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/ViewModel/RelationshipViewModel.swift b/MastodonSDK/Sources/MastodonUI/ViewModel/RelationshipViewModel.swift new file mode 100644 index 00000000..cee31c14 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/ViewModel/RelationshipViewModel.swift @@ -0,0 +1,253 @@ +// +// RelationshipViewModel.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import UIKit +import Combine +import MastodonAsset +import MastodonLocalization +import CoreDataStack + +public enum RelationshipAction: Int, CaseIterable { + case isMyself + case followingBy + case blockingBy + case none // set hide from UI + case follow + case request + case pending + case following + case muting + case blocked + case blocking + case suspended + case edit + case editing + case updating + + public var option: RelationshipActionOptionSet { + return RelationshipActionOptionSet(rawValue: 1 << rawValue) + } +} + +// construct option set on the enum for safe iterator +public struct RelationshipActionOptionSet: OptionSet { + + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + + public static let isMyself = RelationshipAction.isMyself.option + public static let followingBy = RelationshipAction.followingBy.option + public static let blockingBy = RelationshipAction.blockingBy.option + public static let none = RelationshipAction.none.option + public static let follow = RelationshipAction.follow.option + public static let request = RelationshipAction.request.option + public static let pending = RelationshipAction.pending.option + public static let following = RelationshipAction.following.option + public static let muting = RelationshipAction.muting.option + public static let blocked = RelationshipAction.blocked.option + public static let blocking = RelationshipAction.blocking.option + public static let suspended = RelationshipAction.suspended.option + public static let edit = RelationshipAction.edit.option + public static let editing = RelationshipAction.editing.option + public static let updating = RelationshipAction.updating.option + + public static let editOptions: RelationshipActionOptionSet = [.edit, .editing, .updating] + + public func highPriorityAction(except: RelationshipActionOptionSet) -> RelationshipAction? { + let set = subtracting(except) + for action in RelationshipAction.allCases.reversed() where set.contains(action.option) { + return action + } + + return nil + } + + public var title: String { + guard let highPriorityAction = self.highPriorityAction(except: []) else { + assertionFailure() + return " " + } + switch highPriorityAction { + case .isMyself: return "" + case .followingBy: return " " + case .blockingBy: return " " + case .none: return " " + case .follow: return L10n.Common.Controls.Friendship.follow + case .request: return L10n.Common.Controls.Friendship.request + case .pending: return L10n.Common.Controls.Friendship.pending + case .following: return L10n.Common.Controls.Friendship.following + case .muting: return L10n.Common.Controls.Friendship.muted + case .blocked: return L10n.Common.Controls.Friendship.follow // blocked by user + case .blocking: return L10n.Common.Controls.Friendship.blocked + case .suspended: return L10n.Common.Controls.Friendship.follow + case .edit: return L10n.Common.Controls.Friendship.editInfo + case .editing: return L10n.Common.Controls.Actions.done + case .updating: return " " + } + } + +} + +public final class RelationshipViewModel { + + var disposeBag = Set() + + public var userObserver: AnyCancellable? + public var meObserver: AnyCancellable? + + // input + @Published public var user: MastodonUser? + @Published public var me: MastodonUser? + public let relationshipUpdatePublisher = CurrentValueSubject(Void()) // needs initial event + + // output + @Published public var isMyself = false + @Published public var optionSet: RelationshipActionOptionSet? + + @Published public var isFollowing = false + @Published public var isFollowingBy = false + @Published public var isMuting = false + @Published public var isBlocking = false + @Published public var isBlockingBy = false + + public init() { + Publishers.CombineLatest3( + $user, + $me, + relationshipUpdatePublisher + ) + .sink { [weak self] user, me, _ in + guard let self = self else { return } + self.update(user: user, me: me) + + guard let user = user, let me = me else { + self.userObserver = nil + self.meObserver = nil + return + } + + // do not modify object to prevent infinity loop + self.userObserver = RelationshipViewModel.createObjectChangePublisher(user: user) + .sink { [weak self] _ in + guard let self = self else { return } + self.relationshipUpdatePublisher.send() + } + + self.meObserver = RelationshipViewModel.createObjectChangePublisher(user: me) + .sink { [weak self] _ in + guard let self = self else { return } + self.relationshipUpdatePublisher.send() + } + } + .store(in: &disposeBag) + } + +} + +extension RelationshipViewModel { + + public static func createObjectChangePublisher(user: MastodonUser) -> AnyPublisher { + return ManagedObjectObserver + .observe(object: user) + .map { _ in Void() } + .catch { error in + return Just(Void()) + } + .eraseToAnyPublisher() + } + +} + +extension RelationshipViewModel { + private func update(user: MastodonUser?, me: MastodonUser?) { + guard let user = user, + let me = me + else { + reset() + return + } + + let optionSet = RelationshipViewModel.optionSet(user: user, me: me) + + self.isMyself = optionSet.contains(.isMyself) + self.isFollowingBy = optionSet.contains(.followingBy) + self.isFollowing = optionSet.contains(.following) + self.isMuting = optionSet.contains(.muting) + self.isBlockingBy = optionSet.contains(.blockingBy) + self.isBlocking = optionSet.contains(.blocking) + + + self.optionSet = optionSet + } + + private func reset() { + isMyself = false + isFollowingBy = false + isFollowing = false + isMuting = false + isBlockingBy = false + isBlocking = false + optionSet = nil + } +} + +extension RelationshipViewModel { + + public static func optionSet(user: MastodonUser, me: MastodonUser) -> RelationshipActionOptionSet { + let isMyself = user.id == me.id && user.domain == me.domain + guard !isMyself else { + return [.isMyself] + } + + let isProtected = user.locked + let isFollowingBy = me.followingBy.contains(user) + let isFollowing = user.followingBy.contains(me) + let isPending = user.followRequestedBy.contains(me) + let isMuting = user.mutingBy.contains(me) + let isBlockingBy = me.blockingBy.contains(user) + let isBlocking = user.blockingBy.contains(me) + + var optionSet: RelationshipActionOptionSet = [.follow] + + if isMyself { + optionSet.insert(.isMyself) + } + + if isProtected { + optionSet.insert(.request) + } + + if isFollowingBy { + optionSet.insert(.followingBy) + } + + if isFollowing { + optionSet.insert(.following) + } + + if isPending { + optionSet.insert(.pending) + } + + if isMuting { + optionSet.insert(.muting) + } + + if isBlockingBy { + optionSet.insert(.blockingBy) + } + + if isBlocking { + optionSet.insert(.blocking) + } + + return optionSet + } +} From f5aaf2737f3c85814c24c1c9eceb17ce75cf0dc8 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 15 Apr 2022 17:17:39 +0800 Subject: [PATCH 127/188] feat: add discovery endpoint check logic and handle relationship action --- .../Discovery/DiscoverySection.swift | 9 +- .../Provider/DataSourceFacade+Profile.swift | 18 ++-- .../Discovery/DiscoveryViewController.swift | 79 ++++++++++----- .../Scene/Discovery/DiscoveryViewModel.swift | 96 +++++++++++++++---- .../DiscoveryForYouViewController.swift | 21 +++- .../DiscoveryForYouViewModel+Diffable.swift | 8 +- .../News/DiscoveryNewsViewModel+State.swift | 8 +- .../News/DiscoveryNewsViewModel.swift | 25 ++++- .../Posts/DiscoveryPostsViewModel+State.swift | 9 +- .../Posts/DiscoveryPostsViewModel.swift | 22 +++++ .../Content/ProfileCardView+ViewModel.swift | 40 ++++++++ .../View/Content/ProfileCardView.swift | 26 ++++- .../ProfileCardTableViewCell.swift | 14 +++ 13 files changed, 313 insertions(+), 62 deletions(-) diff --git a/Mastodon/Diffiable/Discovery/DiscoverySection.swift b/Mastodon/Diffiable/Discovery/DiscoverySection.swift index f0c358a1..76cc9c03 100644 --- a/Mastodon/Diffiable/Discovery/DiscoverySection.swift +++ b/Mastodon/Diffiable/Discovery/DiscoverySection.swift @@ -20,7 +20,13 @@ extension DiscoverySection { static let logger = Logger(subsystem: "DiscoverySection", category: "logic") - struct Configuration { } + class Configuration { + weak var profileCardTableViewCellDelegate: ProfileCardTableViewCellDelegate? + + public init(profileCardTableViewCellDelegate: ProfileCardTableViewCellDelegate? = nil) { + self.profileCardTableViewCellDelegate = profileCardTableViewCellDelegate + } + } static func diffableDataSource( tableView: UITableView, @@ -52,6 +58,7 @@ extension DiscoverySection { .map { $0?.user } .assign(to: \.me, on: cell.profileCardView.viewModel.relationshipViewModel) .store(in: &cell.disposeBag) + cell.delegate = configuration.profileCardTableViewCellDelegate return cell case .bottomLoader: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift index 36eaab62..66259a09 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift @@ -122,12 +122,12 @@ extension DataSourceFacade { let barButtonItem: UIBarButtonItem? } - @MainActor - static func createProfileActionMenu( - dependency: NeedsDependency, - user: ManagedObjectRecord - ) -> UIMenu { - var children: [UIMenuElement] = [] +// @MainActor +// static func createProfileActionMenu( +// dependency: NeedsDependency, +// user: ManagedObjectRecord +// ) -> UIMenu { +// var children: [UIMenuElement] = [] // let name = mastodonUser.displayNameWithFallback // // if let shareUser = shareUser { @@ -339,9 +339,9 @@ extension DataSourceFacade { // } // children.append(deleteAction) // } - - return UIMenu(title: "", options: [], children: children) - } +// +// return UIMenu(title: "", options: [], children: children) +// } static func createActivityViewController( dependency: NeedsDependency, diff --git a/Mastodon/Scene/Discovery/DiscoveryViewController.swift b/Mastodon/Scene/Discovery/DiscoveryViewController.swift index dac2c99c..8e3aab64 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewController.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewController.swift @@ -29,13 +29,54 @@ public class DiscoveryViewController: TabmanViewController, NeedsDependency { coordinator: coordinator ) - let buttonBar: TMBar.ButtonBar = { + private(set) lazy var buttonBar: TMBar.ButtonBar = { let buttonBar = TMBar.ButtonBar() - buttonBar.indicator.backgroundColor = Asset.Colors.Label.primary.color + buttonBar.backgroundView.style = .custom(view: buttonBarBackgroundView) + buttonBar.layout.interButtonSpacing = 0 buttonBar.layout.contentInset = .zero + buttonBar.indicator.backgroundColor = Asset.Colors.Label.primary.color + buttonBar.indicator.weight = .custom(value: 2) return buttonBar }() + let buttonBarBackgroundView: UIView = { + let view = UIView() + let barBottomLine = UIView.separatorLine + barBottomLine.backgroundColor = Asset.Colors.Label.secondary.color.withAlphaComponent(0.5) + barBottomLine.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(barBottomLine) + NSLayoutConstraint.activate([ + barBottomLine.leadingAnchor.constraint(equalTo: view.leadingAnchor), + barBottomLine.trailingAnchor.constraint(equalTo: view.trailingAnchor), + barBottomLine.bottomAnchor.constraint(equalTo: view.bottomAnchor), + barBottomLine.heightAnchor.constraint(equalToConstant: 2).priority(.required - 1), + ]) + return view + }() + + func customizeButtonBarAppearance() { + // The implmention use CATextlayer. Adapt for Dark Mode without dynamic colors + // Needs trigger update when `userInterfaceStyle` chagnes + let userInterfaceStyle = traitCollection.userInterfaceStyle + buttonBar.buttons.customize { button in + switch userInterfaceStyle { + case .dark: + // Asset.Colors.Label.primary.color + button.selectedTintColor = UIColor(red: 238.0/255.0, green: 238.0/255.0, blue: 238.0/255.0, alpha: 1.0) + // Asset.Colors.Label.secondary.color + button.tintColor = UIColor(red: 151.0/255.0, green: 157.0/255.0, blue: 173.0/255.0, alpha: 1.0) + default: + // Asset.Colors.Label.primary.color + button.selectedTintColor = UIColor(red: 40.0/255.0, green: 44.0/255.0, blue: 55.0/255.0, alpha: 1.0) + // Asset.Colors.Label.secondary.color + button.tintColor = UIColor(red: 60.0/255.0, green: 60.0/255.0, blue: 67.0/255.0, alpha: 0.6) + } + + button.backgroundColor = .clear + button.contentInset = UIEdgeInsets(top: 12, left: 26, bottom: 12, right: 26) + } + } + } extension DiscoveryViewController { @@ -58,13 +99,21 @@ extension DiscoveryViewController { dataSource: viewModel, at: .top ) - updateBarButtonInsets() + customizeButtonBarAppearance() + + viewModel.$viewControllers + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.reloadData() + } + .store(in: &disposeBag) } public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - - updateBarButtonInsets() + + customizeButtonBarAppearance() } } @@ -72,24 +121,8 @@ extension DiscoveryViewController { extension DiscoveryViewController { private func setupAppearance(theme: Theme) { - view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor - buttonBar.backgroundView.style = .flat(color: theme.systemBackgroundColor) - } - - private func updateBarButtonInsets() { - let margin: CGFloat = { - switch traitCollection.userInterfaceIdiom { - case .phone: - return DiscoveryViewController.containerViewMarginForCompactHorizontalSizeClass - default: - return traitCollection.horizontalSizeClass == .regular ? - DiscoveryViewController.containerViewMarginForRegularHorizontalSizeClass : - DiscoveryViewController.containerViewMarginForCompactHorizontalSizeClass - } - }() - - buttonBar.layout.contentInset.left = margin - buttonBar.layout.contentInset.right = margin + view.backgroundColor = theme.secondarySystemBackgroundColor + buttonBarBackgroundView.backgroundColor = theme.systemBackgroundColor } } diff --git a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift index 187d7311..ae31797e 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift @@ -6,11 +6,14 @@ // import UIKit +import Combine import Tabman import Pageboy final class DiscoveryViewModel { + var disposeBag = Set() + // input let context: AppContext let discoveryPostsViewController: DiscoveryPostsViewController @@ -18,25 +21,7 @@ final class DiscoveryViewModel { let discoveryNewsViewController: DiscoveryNewsViewController let discoveryForYouViewController: DiscoveryForYouViewController - // output - let barItems: [TMBarItemable] = { - let items = [ - TMBarItem(title: "Posts"), - TMBarItem(title: "Hashtags"), - TMBarItem(title: "News"), - TMBarItem(title: "For You"), - ] - return items - }() - - var viewControllers: [ScrollViewContainer] { - return [ - discoveryPostsViewController, - discoveryHashtagsViewController, - discoveryNewsViewController, - discoveryForYouViewController, - ] - } + @Published var viewControllers: [ScrollViewContainer & PageViewController] init(context: AppContext, coordinator: SceneCoordinator) { func setupDependency(_ needsDependency: NeedsDependency) { @@ -69,7 +54,35 @@ final class DiscoveryViewModel { viewController.viewModel = DiscoveryForYouViewModel(context: context) return viewController }() + self.viewControllers = [ + discoveryPostsViewController, + discoveryHashtagsViewController, + discoveryNewsViewController, + discoveryForYouViewController, + ] // end init + + discoveryPostsViewController.viewModel.$isServerSupportEndpoint + .receive(on: DispatchQueue.main) + .sink { [weak self] isServerSupportEndpoint in + guard let self = self else { return } + if !isServerSupportEndpoint { + self.viewControllers.removeAll(where: { + $0 === self.discoveryPostsViewController || $0 === self.discoveryPostsViewController + }) + } + } + .store(in: &disposeBag) + + discoveryNewsViewController.viewModel.$isServerSupportEndpoint + .receive(on: DispatchQueue.main) + .sink { [weak self] isServerSupportEndpoint in + guard let self = self else { return } + if !isServerSupportEndpoint { + self.viewControllers.removeAll(where: { $0 === self.discoveryNewsViewController }) + } + } + .store(in: &disposeBag) } } @@ -95,6 +108,49 @@ extension DiscoveryViewModel: PageboyViewControllerDataSource { // MARK: - TMBarDataSource extension DiscoveryViewModel: TMBarDataSource { func barItem(for bar: TMBar, at index: Int) -> TMBarItemable { - return barItems[index] + guard !viewControllers.isEmpty, index < viewControllers.count else { + assertionFailure() + return TMBarItem(title: "") + } + return viewControllers[index].tabItem + } +} + +protocol PageViewController: UIViewController { + var tabItemTitle: String { get } + var tabItem: TMBarItemable { get } +} + +// MARK: - PageViewController +extension DiscoveryPostsViewController: PageViewController { + var tabItemTitle: String { "Posts" } + var tabItem: TMBarItemable { + return TMBarItem(title: tabItemTitle) + } +} + + +// MARK: - PageViewController +extension DiscoveryHashtagsViewController: PageViewController { + var tabItemTitle: String { "Hashtags" } + var tabItem: TMBarItemable { + + return TMBarItem(title: tabItemTitle) + } +} + +// MARK: - PageViewController +extension DiscoveryNewsViewController: PageViewController { + var tabItemTitle: String { "News" } + var tabItem: TMBarItemable { + return TMBarItem(title: tabItemTitle) + } +} + +// MARK: - PageViewController +extension DiscoveryForYouViewController: PageViewController { + var tabItemTitle: String { "For You" } + var tabItem: TMBarItemable { + return TMBarItem(title: tabItemTitle) } } diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift index 4654769d..b8b8f25a 100644 --- a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift @@ -64,7 +64,8 @@ extension DiscoveryForYouViewController { tableView.delegate = self viewModel.setupDiffableDataSource( - tableView: tableView + tableView: tableView, + profileCardTableViewCellDelegate: self ) tableView.refreshControl = refreshControl @@ -119,9 +120,27 @@ extension DiscoveryForYouViewController: UITableViewDelegate { } +// MARK: - ProfileCardTableViewCellDelegate +extension DiscoveryForYouViewController: ProfileCardTableViewCellDelegate { + func profileCardTableViewCell(_ cell: ProfileCardTableViewCell, profileCardView: ProfileCardView, relationshipButtonDidPressed button: ProfileRelationshipActionButton) { + guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else { return } + guard let indexPath = tableView.indexPath(for: cell) else { return } + guard case let .user(record) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return } + + Task { + try await DataSourceFacade.responseToUserFollowAction( + dependency: self, + user: record, + authenticationBox: authenticationBox + ) + } // end Task + } +} + // MARK: ScrollViewContainer extension DiscoveryForYouViewController: ScrollViewContainer { var scrollView: UIScrollView? { tableView } } + diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift index 23114073..fe53cf22 100644 --- a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift @@ -7,16 +7,20 @@ import UIKit import Combine +import MastodonUI extension DiscoveryForYouViewModel { func setupDiffableDataSource( - tableView: UITableView + tableView: UITableView, + profileCardTableViewCellDelegate: ProfileCardTableViewCellDelegate ) { diffableDataSource = DiscoverySection.diffableDataSource( tableView: tableView, context: context, - configuration: DiscoverySection.Configuration() + configuration: DiscoverySection.Configuration( + profileCardTableViewCellDelegate: profileCardTableViewCellDelegate + ) ) Task { diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift index 37d93e5b..8da975de 100644 --- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift @@ -183,7 +183,13 @@ extension DiscoveryNewsViewModel.State { viewModel.didLoadLatest.send() } catch { logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch news fail: \(error.localizedDescription)") - await enter(state: Fail.self) + if let error = error as? Mastodon.API.Error, error.httpResponseStatus.code == 404 { + viewModel.isServerSupportEndpoint = false + await enter(state: NoMore.self) + } else { + await enter(state: Fail.self) + } + viewModel.didLoadLatest.send() } } // end Task diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift index b87e7c05..2c4d89dc 100644 --- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift @@ -38,10 +38,15 @@ final class DiscoveryNewsViewModel { }() let didLoadLatest = PassthroughSubject() - + @Published var isServerSupportEndpoint = true + init(context: AppContext) { self.context = context // end init + + Task { + await checkServerEndpoint() + } // end Task } deinit { @@ -49,3 +54,21 @@ final class DiscoveryNewsViewModel { } } + + +extension DiscoveryNewsViewModel { + func checkServerEndpoint() async { + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } + + do { + _ = try await context.apiService.trendLinks( + domain: authenticationBox.domain, + query: .init(offset: nil, limit: nil) + ) + } catch let error as Mastodon.API.Error where error.httpResponseStatus.code == 404 { + isServerSupportEndpoint = false + } catch { + // do nothing + } + } +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift index a8e2e7c2..d91c5adc 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift @@ -180,9 +180,16 @@ extension DiscoveryPostsViewModel.State { } viewModel.statusFetchedResultsController.statusIDs.value = statusIDs viewModel.didLoadLatest.send() +// } catch let error as? } catch { logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch posts fail: \(error.localizedDescription)") - await enter(state: Fail.self) + if let error = error as? Mastodon.API.Error, error.httpResponseStatus.code == 404 { + viewModel.isServerSupportEndpoint = false + await enter(state: NoMore.self) + } else { + await enter(state: Fail.self) + } + viewModel.didLoadLatest.send() } } // end Task diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift index 590ccc16..c001bb7b 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift @@ -38,6 +38,7 @@ final class DiscoveryPostsViewModel { }() let didLoadLatest = PassthroughSubject() + @Published var isServerSupportEndpoint = true init(context: AppContext) { self.context = context @@ -52,6 +53,10 @@ final class DiscoveryPostsViewModel { .map { $0?.domain } .assign(to: \.value, on: statusFetchedResultsController.domain) .store(in: &disposeBag) + + Task { + await checkServerEndpoint() + } // end Task } deinit { @@ -59,3 +64,20 @@ final class DiscoveryPostsViewModel { } } + +extension DiscoveryPostsViewModel { + func checkServerEndpoint() async { + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } + + do { + _ = try await context.apiService.trendStatuses( + domain: authenticationBox.domain, + query: .init(offset: nil, limit: nil) + ) + } catch let error as Mastodon.API.Error where error.httpResponseStatus.code == 404 { + isServerSupportEndpoint = false + } catch { + // do nothing + } + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift index 0e01161d..99eb27a5 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift @@ -12,6 +12,7 @@ import Meta import AlamofireImage import CoreDataStack import MastodonLocalization +import MastodonAsset extension ProfileCardView { public class ViewModel: ObservableObject { @@ -19,6 +20,9 @@ extension ProfileCardView { var disposeBag = Set() public let relationshipViewModel = RelationshipViewModel() + + @Published public var userInterfaceStyle: UIUserInterfaceStyle? + @Published public var backgroundColor: UIColor? // Author @Published public var authorBannerImageURL: URL? @@ -37,11 +41,35 @@ extension ProfileCardView { @Published public var isMuting = false @Published public var isBlocking = false @Published public var isBlockedBy = false + + init() { + backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor + Publishers.CombineLatest( + ThemeService.shared.currentTheme, + $userInterfaceStyle + ) + .sink { [weak self] theme, userInterfaceStyle in + guard let self = self else { return } + guard let userInterfaceStyle = userInterfaceStyle else { return } + switch userInterfaceStyle { + case .dark: + self.backgroundColor = theme.systemBackgroundColor + case .light, .unspecified: + self.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color + @unknown default: + self.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color + assertionFailure() + // do nothing + } + } + .store(in: &disposeBag) + } } } extension ProfileCardView.ViewModel { func bind(view: ProfileCardView) { + bindAppearacne(view: view) bindHeader(view: view) bindUser(view: view) bindBio(view: view) @@ -49,6 +77,18 @@ extension ProfileCardView.ViewModel { bindDashboard(view: view) } + private func bindAppearacne(view: ProfileCardView) { + userInterfaceStyle = view.traitCollection.userInterfaceStyle + + $backgroundColor + .assign(to: \.backgroundColor, on: view.container) + .store(in: &disposeBag) + $backgroundColor + .assign(to: \.backgroundColor, on: view.avatarButtonBackgroundView) + .store(in: &disposeBag) + } + + private func bindHeader(view: ProfileCardView) { $authorBannerImageURL .sink { url in diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift index a8e90906..eb500b7c 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -5,17 +5,23 @@ // Created by MainasuK on 2022-4-14. // +import os.log import UIKit import Combine import MetaTextKit import MastodonAsset +public protocol ProfileCardViewDelegate: AnyObject { + func profileCardView(_ profileCardView: ProfileCardView, relationshipButtonDidPressed button: ProfileRelationshipActionButton) +} + public final class ProfileCardView: UIView { static let avatarSize = CGSize(width: 56, height: 56) static let friendshipActionButtonSize = CGSize(width: 108, height: 34) static let contentMargin: CGFloat = 16 + weak var delegate: ProfileCardViewDelegate? private var _disposeBag = Set() var disposeBag = Set() @@ -31,6 +37,7 @@ public final class ProfileCardView: UIView { }() // avatar + public let avatarButtonBackgroundView = UIView() public let avatarButton = AvatarButton() // author name @@ -115,7 +122,6 @@ extension ProfileCardView { statusDashboardView.isUserInteractionEnabled = false // container: V - [ bannerContainer | authorContainer | bioMetaText | infoContainer ] - container.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color container.axis = .vertical container.spacing = 8 container.translatesAutoresizingMaskIntoConstraints = false @@ -171,8 +177,6 @@ extension ProfileCardView { avatarButton.heightAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.height).priority(.required - 1), ]) - let avatarButtonBackgroundView = UIView() - avatarButtonBackgroundView.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color avatarButtonBackgroundView.layer.masksToBounds = true avatarButtonBackgroundView.layer.cornerCurve = .continuous avatarButtonBackgroundView.layer.cornerRadius = 12 @@ -230,6 +234,22 @@ extension ProfileCardView { NSLayoutConstraint.activate([ bottomPadding.heightAnchor.constraint(equalToConstant: 16) ]) + + relationshipActionButton.addTarget(self, action: #selector(ProfileCardView.relationshipActionButtonDidPressed(_:)), for: .touchUpInside) + } + + public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + viewModel.userInterfaceStyle = traitCollection.userInterfaceStyle } } + +extension ProfileCardView { + @objc private func relationshipActionButtonDidPressed(_ sender: UIButton) { + os_log(.debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + assert(sender === relationshipActionButton) + delegate?.profileCardView(self, relationshipButtonDidPressed: relationshipActionButton) + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift index a793482a..d3c8f223 100644 --- a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift @@ -8,8 +8,13 @@ import UIKit import Combine +public protocol ProfileCardTableViewCellDelegate: AnyObject { + func profileCardTableViewCell(_ cell: ProfileCardTableViewCell, profileCardView: ProfileCardView, relationshipButtonDidPressed button: ProfileRelationshipActionButton) +} + public final class ProfileCardTableViewCell: UITableViewCell { + public weak var delegate: ProfileCardTableViewCellDelegate? public var disposeBag = Set() public let profileCardView: ProfileCardView = { @@ -63,6 +68,15 @@ extension ProfileCardTableViewCell { profileCardView.trailingAnchor.constraint(equalTo: shadowBackgroundContainer.trailingAnchor), profileCardView.bottomAnchor.constraint(equalTo: shadowBackgroundContainer.bottomAnchor), ]) + + profileCardView.delegate = self } } + +// MARK: - ProfileCardViewDelegate +extension ProfileCardTableViewCell: ProfileCardViewDelegate { + public func profileCardView(_ profileCardView: ProfileCardView, relationshipButtonDidPressed button: ProfileRelationshipActionButton) { + delegate?.profileCardTableViewCell(self, profileCardView: profileCardView, relationshipButtonDidPressed: button) + } +} From 8a33ed9f9fca2ffc6e4ffcf5b140932f5a4d9b36 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 15 Apr 2022 17:20:41 +0800 Subject: [PATCH 128/188] fix: search bar active with re-layout animation on iPad device issue --- Mastodon/Coordinator/SceneCoordinator.swift | 6 +- .../Search/Search/SearchViewController.swift | 110 ++++++++++-------- .../Search/SearchViewModel+Diffable.swift | 64 +++++----- .../Scene/Search/Search/SearchViewModel.swift | 50 ++++---- .../SearchDetailViewController.swift | 26 ++++- ...lViewControllerAnimatedTransitioning.swift | 7 +- 6 files changed, 144 insertions(+), 119 deletions(-) diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index c8ce4acb..1f803001 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -144,7 +144,7 @@ extension SceneCoordinator { case popover(sourceView: UIView) case panModal case custom(transitioningDelegate: UIViewControllerTransitioningDelegate) - case customPush + case customPush(animated: Bool) case safariPresent(animated: Bool, completion: (() -> Void)? = nil) case alertController(animated: Bool, completion: (() -> Void)? = nil) case activityViewControllerPresent(animated: Bool, completion: (() -> Void)? = nil) @@ -339,10 +339,10 @@ extension SceneCoordinator { viewController.transitioningDelegate = transitioningDelegate (splitViewController ?? presentingViewController)?.present(viewController, animated: true, completion: nil) - case .customPush: + case .customPush(let animated): // set delegate in view controller assert(sender?.navigationController?.delegate != nil) - sender?.navigationController?.pushViewController(viewController, animated: true) + sender?.navigationController?.pushViewController(viewController, animated: animated) case .safariPresent(let animated, let completion): if UserDefaults.shared.preferredUsingDefaultBrowser, case let .safari(url) = scene { diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift index 6f4d2200..7594eb47 100644 --- a/Mastodon/Scene/Search/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/Search/SearchViewController.swift @@ -15,7 +15,7 @@ import MastodonLocalization final class HeightFixedSearchBar: UISearchBar { override var intrinsicContentSize: CGSize { - return CGSize(width: CGFloat.greatestFiniteMagnitude, height: 44) + return CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) } } @@ -35,20 +35,20 @@ final class SearchViewController: UIViewController, NeedsDependency { // layout alongside with split mode button (on iPad) let titleViewContainer = UIView() let searchBar = HeightFixedSearchBar() - - let collectionView: UICollectionView = { - var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) - configuration.backgroundColor = .clear - configuration.headerMode = .supplementary - let layout = UICollectionViewCompositionalLayout.list(using: configuration) - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - collectionView.backgroundColor = .clear - return collectionView - }() + +// let collectionView: UICollectionView = { +// var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) +// configuration.backgroundColor = .clear +// configuration.headerMode = .supplementary +// let layout = UICollectionViewCompositionalLayout.list(using: configuration) +// let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) +// collectionView.backgroundColor = .clear +// return collectionView +// }() let searchBarTapPublisher = PassthroughSubject() - private(set) lazy var trendViewController: DiscoveryViewController = { + private(set) lazy var discoveryViewController: DiscoveryViewController = { let viewController = DiscoveryViewController() viewController.context = context viewController.coordinator = coordinator @@ -78,29 +78,31 @@ extension SearchViewController { setupSearchBar() - collectionView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(collectionView) +// collectionView.translatesAutoresizingMaskIntoConstraints = false +// view.addSubview(collectionView) +// NSLayoutConstraint.activate([ +// collectionView.topAnchor.constraint(equalTo: view.topAnchor), +// collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), +// collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), +// collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor), +// ]) +// +// collectionView.delegate = self +// viewModel.setupDiffableDataSource( +// collectionView: collectionView +// ) + + addChild(discoveryViewController) + discoveryViewController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(discoveryViewController.view) NSLayoutConstraint.activate([ - collectionView.topAnchor.constraint(equalTo: view.topAnchor), - collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + discoveryViewController.view.topAnchor.constraint(equalTo: view.topAnchor), + discoveryViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + discoveryViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + discoveryViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - collectionView.delegate = self - viewModel.setupDiffableDataSource( - collectionView: collectionView - ) - - addChild(trendViewController) - trendViewController.view.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(trendViewController.view) - NSLayoutConstraint.activate([ - trendViewController.view.topAnchor.constraint(equalTo: view.topAnchor), - trendViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), - trendViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), - trendViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) +// discoveryViewController.view.isHidden = true } override func viewDidAppear(_ animated: Bool) { @@ -130,7 +132,10 @@ extension SearchViewController { searchBar.trailingAnchor.constraint(equalTo: titleViewContainer.trailingAnchor), searchBar.bottomAnchor.constraint(equalTo: titleViewContainer.bottomAnchor), ]) + searchBar.setContentHuggingPriority(.required, for: .horizontal) + searchBar.setContentHuggingPriority(.required, for: .vertical) navigationItem.titleView = titleViewContainer +// navigationItem.titleView = searchBar searchBarTapPublisher .throttle(for: 0.5, scheduler: DispatchQueue.main, latest: false) @@ -140,7 +145,10 @@ extension SearchViewController { let searchDetailViewModel = SearchDetailViewModel() searchDetailViewModel.needsBecomeFirstResponder = true self.navigationController?.delegate = self.searchTransitionController - self.coordinator.present(scene: .searchDetail(viewModel: searchDetailViewModel), from: self, transition: .customPush) + // FIXME: + // use `.customPush(animated: false)` false to disable navigation bar animation for searchBar layout + // but that should be a fade transition whe fixed size searchBar + self.coordinator.present(scene: .searchDetail(viewModel: searchDetailViewModel), from: self, transition: .customPush(animated: false)) } .store(in: &disposeBag) } @@ -168,21 +176,21 @@ extension SearchViewController: UISearchControllerDelegate { } // MARK: - UICollectionViewDelegate -extension SearchViewController: UICollectionViewDelegate { - func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): select item at: \(indexPath.debugDescription)") - - defer { - collectionView.deselectItem(at: indexPath, animated: true) - } - - guard let diffableDataSource = viewModel.diffableDataSource else { return } - guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } - - switch item { - case .trend(let hashtag): - let viewModel = HashtagTimelineViewModel(context: context, hashtag: hashtag.name) - coordinator.present(scene: .hashtagTimeline(viewModel: viewModel), from: self, transition: .show) - } - } -} +//extension SearchViewController: UICollectionViewDelegate { +// func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { +// logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): select item at: \(indexPath.debugDescription)") +// +// defer { +// collectionView.deselectItem(at: indexPath, animated: true) +// } +// +// guard let diffableDataSource = viewModel.diffableDataSource else { return } +// guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } +// +// switch item { +// case .trend(let hashtag): +// let viewModel = HashtagTimelineViewModel(context: context, hashtag: hashtag.name) +// coordinator.present(scene: .hashtagTimeline(viewModel: viewModel), from: self, transition: .show) +// } +// } +//} diff --git a/Mastodon/Scene/Search/Search/SearchViewModel+Diffable.swift b/Mastodon/Scene/Search/Search/SearchViewModel+Diffable.swift index ca741b7f..3f448289 100644 --- a/Mastodon/Scene/Search/Search/SearchViewModel+Diffable.swift +++ b/Mastodon/Scene/Search/Search/SearchViewModel+Diffable.swift @@ -8,35 +8,35 @@ import UIKit import MastodonSDK -extension SearchViewModel { - - func setupDiffableDataSource( - collectionView: UICollectionView - ) { - diffableDataSource = SearchSection.diffableDataSource( - collectionView: collectionView, - context: context - ) - - var snapshot = NSDiffableDataSourceSnapshot() - snapshot.appendSections([.trend]) - diffableDataSource?.apply(snapshot) - - $hashtags - .receive(on: DispatchQueue.main) - .sink { [weak self] hashtags in - guard let self = self else { return } - guard let diffableDataSource = self.diffableDataSource else { return } - - var snapshot = NSDiffableDataSourceSnapshot() - snapshot.appendSections([.trend]) - - let trendItems = hashtags.map { SearchItem.trend($0) } - snapshot.appendItems(trendItems, toSection: .trend) - - diffableDataSource.apply(snapshot) - } - .store(in: &disposeBag) - } - -} +//extension SearchViewModel { +// +// func setupDiffableDataSource( +// collectionView: UICollectionView +// ) { +// diffableDataSource = SearchSection.diffableDataSource( +// collectionView: collectionView, +// context: context +// ) +// +// var snapshot = NSDiffableDataSourceSnapshot() +// snapshot.appendSections([.trend]) +// diffableDataSource?.apply(snapshot) +// +// $hashtags +// .receive(on: DispatchQueue.main) +// .sink { [weak self] hashtags in +// guard let self = self else { return } +// guard let diffableDataSource = self.diffableDataSource else { return } +// +// var snapshot = NSDiffableDataSourceSnapshot() +// snapshot.appendSections([.trend]) +// +// let trendItems = hashtags.map { SearchItem.trend($0) } +// snapshot.appendItems(trendItems, toSection: .trend) +// +// diffableDataSource.apply(snapshot) +// } +// .store(in: &disposeBag) +// } +// +//} diff --git a/Mastodon/Scene/Search/Search/SearchViewModel.swift b/Mastodon/Scene/Search/Search/SearchViewModel.swift index 84e09725..b47bc2e8 100644 --- a/Mastodon/Scene/Search/Search/SearchViewModel.swift +++ b/Mastodon/Scene/Search/Search/SearchViewModel.swift @@ -29,31 +29,31 @@ final class SearchViewModel: NSObject { self.context = context super.init() - Publishers.CombineLatest( - context.authenticationService.activeMastodonAuthenticationBox, - viewDidAppeared - ) - .compactMap { authenticationBox, _ -> MastodonAuthenticationBox? in - return authenticationBox - } - .throttle(for: 3, scheduler: DispatchQueue.main, latest: true) - .asyncMap { authenticationBox in - try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil) - } - .retry(3) - .map { response in Result, Error> { response } } - .catch { error in Just(Result, Error> { throw error }) } - .receive(on: DispatchQueue.main) - .sink { [weak self] result in - guard let self = self else { return } - switch result { - case .success(let response): - self.hashtags = response.value - case .failure: - break - } - } - .store(in: &disposeBag) +// Publishers.CombineLatest( +// context.authenticationService.activeMastodonAuthenticationBox, +// viewDidAppeared +// ) +// .compactMap { authenticationBox, _ -> MastodonAuthenticationBox? in +// return authenticationBox +// } +// .throttle(for: 3, scheduler: DispatchQueue.main, latest: true) +// .asyncMap { authenticationBox in +// try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil) +// } +// .retry(3) +// .map { response in Result, Error> { response } } +// .catch { error in Just(Result, Error> { throw error }) } +// .receive(on: DispatchQueue.main) +// .sink { [weak self] result in +// guard let self = self else { return } +// switch result { +// case .success(let response): +// self.hashtags = response.value +// case .failure: +// break +// } +// } +// .store(in: &disposeBag) } } diff --git a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift index 5e143a33..ecc1c0c0 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift @@ -12,6 +12,14 @@ import Pageboy import MastodonAsset import MastodonLocalization +final class CustomSearchController: UISearchController { + + let customSearchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 300, height: 100)) + + override var searchBar: UISearchBar { customSearchBar } + +} + // Fake search bar not works on iPad with UISplitViewController // check device and fallback to standard UISearchController final class SearchDetailViewController: PageboyViewController, NeedsDependency { @@ -48,8 +56,8 @@ final class SearchDetailViewController: PageboyViewController, NeedsDependency { return navigationBar }() - let searchController: UISearchController = { - let searchController = UISearchController() + let searchController: CustomSearchController = { + let searchController = CustomSearchController() searchController.automaticallyShowsScopeBar = false searchController.dimsBackgroundDuringPresentation = false return searchController @@ -235,11 +243,17 @@ extension SearchDetailViewController { if isPhoneDevice { searchBar.setShowsCancelButton(true, animated: animated) - searchBar.becomeFirstResponder() + UIView.performWithoutAnimation { + self.searchBar.becomeFirstResponder() + } } else { - searchController.isActive = true - DispatchQueue.main.asyncAfter(deadline: .now() + 0.33) { - self.searchController.searchBar.becomeFirstResponder() + searchController.searchBar.setShowsCancelButton(true, animated: false) + searchController.searchBar.setShowsScope(true, animated: false) + UIView.performWithoutAnimation { + self.searchController.isActive = true + } + DispatchQueue.main.async { + self.searchController.searchBar.becomeFirstResponder() } } } diff --git a/Mastodon/Scene/Transition/Search/SearchToSearchDetailViewControllerAnimatedTransitioning.swift b/Mastodon/Scene/Transition/Search/SearchToSearchDetailViewControllerAnimatedTransitioning.swift index f06d04d9..e060acc8 100644 --- a/Mastodon/Scene/Transition/Search/SearchToSearchDetailViewControllerAnimatedTransitioning.swift +++ b/Mastodon/Scene/Transition/Search/SearchToSearchDetailViewControllerAnimatedTransitioning.swift @@ -46,14 +46,17 @@ extension SearchToSearchDetailViewControllerAnimatedTransitioning { let toViewEndFrame = transitionContext.finalFrame(for: toVC) transitionContext.containerView.addSubview(toView) toView.frame = toViewEndFrame + toView.setNeedsLayout() + toView.layoutIfNeeded() + toVC.searchBar.setNeedsLayout() + toVC.searchBar.layoutIfNeeded() toView.alpha = 0 let animator = UIViewPropertyAnimator(duration: transitionDuration(using: transitionContext), curve: curve) animator.addAnimations { - + toView.alpha = 1 } animator.addCompletion { position in - toView.alpha = 1 transitionContext.completeTransition(true) } return animator From 9477071556aaca00a1db0dec46f2a9eff716011b Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 15 Apr 2022 17:22:30 +0800 Subject: [PATCH 129/188] chore: update i18n --- .../MastodonUI/View/Content/NewsView+Configuration.swift | 2 +- .../MastodonUI/View/Content/TrendView+Configuration.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift index 3116534a..e045eafe 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift @@ -14,7 +14,7 @@ extension NewsView { public func configure(link: Mastodon.Entity.Link) { providerNameLabel.text = link.providerName headlineLabel.text = link.title - footnoteLabel.text = L10n.Scene.Search.Recommend.HashTag.peopleTalking(link.talkingPeopleCount ?? 0) + footnoteLabel.text = L10n.Plural.peopleTalking(link.talkingPeopleCount ?? 0) let configuration = MediaView.Configuration( info: .image(info: .init( diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift index cdd3dfd8..fd5ddb24 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift @@ -12,7 +12,7 @@ import MastodonLocalization extension TrendView { public func configure(tag: Mastodon.Entity.Tag) { let primaryLabelText = "#" + tag.name - let secondaryLabelText = L10n.Scene.Search.Recommend.HashTag.peopleTalking(tag.talkingPeopleCount ?? 0) + let secondaryLabelText = L10n.Plural.peopleTalking(tag.talkingPeopleCount ?? 0) primaryLabel.text = primaryLabelText secondaryLabel.text = secondaryLabelText From c3bd5528fa4d7ff1cefe60593e45c3c48dcec05f Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 15 Apr 2022 17:34:58 +0800 Subject: [PATCH 130/188] feat: add reload to Hashtags tab for Discovery scene --- .../DiscoveryHashtagsViewController.swift | 20 +++++++++++++++++++ .../Hashtags/DiscoveryHashtagsViewModel.swift | 13 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift index 1dca1232..91ab5036 100644 --- a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift @@ -31,6 +31,8 @@ final class DiscoveryHashtagsViewController: UIViewController, NeedsDependency, return tableView }() + let refreshControl = UIRefreshControl() + deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } @@ -59,6 +61,9 @@ extension DiscoveryHashtagsViewController { tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) + + tableView.refreshControl = refreshControl + refreshControl.addTarget(self, action: #selector(DiscoveryHashtagsViewController.refreshControlValueChanged(_:)), for: .valueChanged) tableView.delegate = self viewModel.setupDiffableDataSource( @@ -80,6 +85,21 @@ extension DiscoveryHashtagsViewController { } +extension DiscoveryHashtagsViewController { + + @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { + Task { @MainActor in + do { + try await viewModel.fetch() + } catch { + // do nothing + } + sender.endRefreshing() + } // end Task + } + +} + // MARK: - UITableViewDelegate extension DiscoveryHashtagsViewController: UITableViewDelegate { diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift index 5f51d645..bb30ec9e 100644 --- a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift @@ -15,6 +15,8 @@ import MastodonSDK final class DiscoveryHashtagsViewModel { + let logger = Logger(subsystem: "DiscoveryHashtagsViewModel", category: "ViewModel") + var disposeBag = Set() // input @@ -61,3 +63,14 @@ final class DiscoveryHashtagsViewModel { } } + +extension DiscoveryHashtagsViewModel { + + @MainActor + func fetch() async throws { + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } + let response = try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil) + hashtags = response.value.filter { !$0.name.isEmpty } + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch tags: \(response.value.count)") + } +} From 5c1f5eb8f0bdb0cedb3e2a931f857220d2afa7dc Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 15 Apr 2022 17:36:37 +0800 Subject: [PATCH 131/188] chore: update version to 1.3.1 (110) --- AppShared/Info.plist | 4 +-- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 4 +-- MastodonIntent/Info.plist | 4 +-- MastodonTests/Info.plist | 4 +-- MastodonUITests/Info.plist | 4 +-- NotificationService/Info.plist | 4 +-- ShareActionExtension/Info.plist | 4 +-- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 73f11cd2..66a4b22f 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 678fc710..54c68295 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4728,7 +4728,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4757,7 +4757,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4865,11 +4865,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 109; + DYLIB_CURRENT_VERSION = 110; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4896,11 +4896,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 109; + DYLIB_CURRENT_VERSION = 110; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4925,7 +4925,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4950,7 +4950,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4975,7 +4975,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5000,7 +5000,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5086,7 +5086,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5153,11 +5153,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 109; + DYLIB_CURRENT_VERSION = 110; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5182,7 +5182,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5206,7 +5206,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5231,7 +5231,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5256,7 +5256,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5280,7 +5280,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 1444a8b2..e45da3c0 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 22 + 33 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 23 + 32 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 24 + 31 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 311ee390..88b45ec3 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleURLTypes @@ -43,7 +43,7 @@ CFBundleVersion - 109 + 110 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 02385f4e..79748763 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 73f11cd2..66a4b22f 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 73f11cd2..66a4b22f 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 215b572b..7301c57d 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 82ba5658..85681881 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 NSExtension NSExtensionAttributes From 950bb692075ef0e06656636ad3d415ff8c1bed36 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 11:46:48 +0200 Subject: [PATCH 132/188] New translations app.json (Basque) --- .../StringsConvertor/input/eu_ES/app.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Localization/StringsConvertor/input/eu_ES/app.json b/Localization/StringsConvertor/input/eu_ES/app.json index ff249acd..0e8b8e72 100644 --- a/Localization/StringsConvertor/input/eu_ES/app.json +++ b/Localization/StringsConvertor/input/eu_ES/app.json @@ -130,7 +130,7 @@ "show_user_profile": "Erakutsi erabiltzailearen profila", "content_warning": "Edukiaren abisua", "media_content_warning": "Ukitu edonon bistaratzeko", - "tap_to_reveal": "Tap to reveal", + "tap_to_reveal": "Sakatu erakusteko", "poll": { "vote": "Bozkatu", "closed": "Itxita" @@ -143,10 +143,10 @@ "unfavorite": "Kendu gogokoa", "menu": "Menua", "hide": "Ezkutatu", - "show_image": "Show image", - "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_image": "Erakutsi irudia", + "show_gif": "Erakutsi GIFa", + "show_video_player": "Erakutsi bideo-erreproduzigailua", + "tap_then_hold_to_show_menu": "Sakatu eta eutsi menua erakusteko" }, "tag": { "url": "URLa", @@ -447,10 +447,10 @@ } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", - "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "show_avatar_image": "Erakutsi abatarra", + "edit_avatar_image": "Editatu abatarra", + "show_banner_image": "Erakutsi banner irudia", + "double_tap_to_open_the_list": "Sakatu birritan zerrenda irekitzeko" } }, "follower": { @@ -553,7 +553,7 @@ "disable_avatar_animation": "Desgaitu abatar animatuak", "disable_emoji_animation": "Desgaitu emoji animatuak", "using_default_browser": "Erabili nabigatzaile lehenetsia estekak irekitzeko", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "Ireki estekak Mastodonen" }, "boring_zone": { "title": "Eremu aspergarria", From 1995e8fc975ca8595aa126ca1882ec487cd962e3 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 11:46:49 +0200 Subject: [PATCH 133/188] New translations Localizable.stringsdict (Basque) --- .../StringsConvertor/input/eu_ES/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/eu_ES/Localizable.stringsdict b/Localization/StringsConvertor/input/eu_ES/Localizable.stringsdict index 2069e27a..871fb10b 100644 --- a/Localization/StringsConvertor/input/eu_ES/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/eu_ES/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + Erantzun bat other - %ld replies + %ld erantzun plural.count.vote From d6937bbeec83298f0a7c4a608cfe88a9448b099b Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:53:59 +0200 Subject: [PATCH 134/188] New translations app.json (Catalan) --- Localization/StringsConvertor/input/ca_ES/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index b7ff6735..3da2402d 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -492,6 +492,14 @@ "clear": "Neteja" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Els teus Favorits" }, From 3d052ebf08bd0172212cd0011f2681d1c9379aaf Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:00 +0200 Subject: [PATCH 135/188] New translations app.json (Romanian) --- Localization/StringsConvertor/input/ro_RO/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/ro_RO/app.json b/Localization/StringsConvertor/input/ro_RO/app.json index eeb4dc86..1b776e79 100644 --- a/Localization/StringsConvertor/input/ro_RO/app.json +++ b/Localization/StringsConvertor/input/ro_RO/app.json @@ -492,6 +492,14 @@ "clear": "Clear" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, From faf14e5c8c79460de0e624b3e26fa690992f8df6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:01 +0200 Subject: [PATCH 136/188] New translations app.json (German) --- .../StringsConvertor/input/de_DE/app.json | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Localization/StringsConvertor/input/de_DE/app.json b/Localization/StringsConvertor/input/de_DE/app.json index e3601595..522b3f77 100644 --- a/Localization/StringsConvertor/input/de_DE/app.json +++ b/Localization/StringsConvertor/input/de_DE/app.json @@ -130,7 +130,7 @@ "show_user_profile": "Benutzerprofil anzeigen", "content_warning": "Inhaltswarnung", "media_content_warning": "Tippe irgendwo zum Anzeigen", - "tap_to_reveal": "Tap to reveal", + "tap_to_reveal": "Zum Anzeigen tippen", "poll": { "vote": "Abstimmen", "closed": "Beendet" @@ -143,10 +143,10 @@ "unfavorite": "Aus Favoriten entfernen", "menu": "Menü", "hide": "Verstecken", - "show_image": "Show image", - "show_gif": "Show GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_image": "Bild anzeigen", + "show_gif": "GIF anzeigen", + "show_video_player": "Zeige Video-Player", + "tap_then_hold_to_show_menu": "Halte gedrückt um das Menü anzuzeigen" }, "tag": { "url": "URL", @@ -447,10 +447,10 @@ } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", - "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "show_avatar_image": "Profilbild anzeigen", + "edit_avatar_image": "Profilbild bearbeiten", + "show_banner_image": "Bannerbild anzeigen", + "double_tap_to_open_the_list": "Doppeltippen, um die Liste zu öffnen" } }, "follower": { @@ -492,6 +492,14 @@ "clear": "Zurücksetzen" } }, + "discovery": { + "tabs": { + "posts": "Beiträge", + "hashtags": "Hashtags", + "news": "Nachrichten", + "for_you": "Für dich" + } + }, "favorite": { "title": "Deine Favoriten" }, @@ -553,7 +561,7 @@ "disable_avatar_animation": "Animierte Profilbilder deaktivieren", "disable_emoji_animation": "Animierte Emojis deaktivieren", "using_default_browser": "Standardbrowser zum Öffnen von Links verwenden", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "Links in Mastodon öffnen" }, "boring_zone": { "title": "Der langweilige Bereich", From 35bb2796d5f100fff557442aff78658d2bded917 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:02 +0200 Subject: [PATCH 137/188] New translations app.json (Danish) --- Localization/StringsConvertor/input/da_DK/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/da_DK/app.json b/Localization/StringsConvertor/input/da_DK/app.json index f0dc0ebf..548c5ada 100644 --- a/Localization/StringsConvertor/input/da_DK/app.json +++ b/Localization/StringsConvertor/input/da_DK/app.json @@ -492,6 +492,14 @@ "clear": "Clear" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, From 7519c561bae48ab22b7e2509cebe64248fb5d5c4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:03 +0200 Subject: [PATCH 138/188] New translations app.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index 6a6fdcd4..a8831d65 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -492,6 +492,14 @@ "clear": "مَحو" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "مُفضَّلَتُك" }, From 48db0f78753e36cda1e8fc3f28f2c05c76f5bf06 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:04 +0200 Subject: [PATCH 139/188] New translations app.json (French) --- Localization/StringsConvertor/input/fr_FR/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/fr_FR/app.json b/Localization/StringsConvertor/input/fr_FR/app.json index 248253e9..56112082 100644 --- a/Localization/StringsConvertor/input/fr_FR/app.json +++ b/Localization/StringsConvertor/input/fr_FR/app.json @@ -492,6 +492,14 @@ "clear": "Effacer" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Vos favoris" }, From b10e9ed67943a4689705a94626cd8220fd4b07dd Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:05 +0200 Subject: [PATCH 140/188] New translations app.json (Spanish) --- Localization/StringsConvertor/input/es_ES/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/es_ES/app.json b/Localization/StringsConvertor/input/es_ES/app.json index e9f352cb..d4215ecb 100644 --- a/Localization/StringsConvertor/input/es_ES/app.json +++ b/Localization/StringsConvertor/input/es_ES/app.json @@ -492,6 +492,14 @@ "clear": "Borrar" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Tus Favoritos" }, From 11063b8a6f38321e83cfd6ea69617939fa8d7cee Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:06 +0200 Subject: [PATCH 141/188] New translations app.json (English, United States) --- Localization/StringsConvertor/input/en_US/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/en_US/app.json b/Localization/StringsConvertor/input/en_US/app.json index f0dc0ebf..548c5ada 100644 --- a/Localization/StringsConvertor/input/en_US/app.json +++ b/Localization/StringsConvertor/input/en_US/app.json @@ -492,6 +492,14 @@ "clear": "Clear" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, From 89bdb1e981eec437060eef9f5a5284be2e17d8f1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:07 +0200 Subject: [PATCH 142/188] New translations app.json (Welsh) --- Localization/StringsConvertor/input/cy_GB/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/cy_GB/app.json b/Localization/StringsConvertor/input/cy_GB/app.json index f0dc0ebf..548c5ada 100644 --- a/Localization/StringsConvertor/input/cy_GB/app.json +++ b/Localization/StringsConvertor/input/cy_GB/app.json @@ -492,6 +492,14 @@ "clear": "Clear" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, From 84b6f247ff643833b4c55d575158634d981bd6bb Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:08 +0200 Subject: [PATCH 143/188] New translations app.json (Chinese Traditional) --- Localization/StringsConvertor/input/zh_TW/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_TW/app.json b/Localization/StringsConvertor/input/zh_TW/app.json index e1e61323..909bd7c6 100644 --- a/Localization/StringsConvertor/input/zh_TW/app.json +++ b/Localization/StringsConvertor/input/zh_TW/app.json @@ -492,6 +492,14 @@ "clear": "Clear" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, From b941437c9f84ce29ffcfc2cba0c5a7cba1c07ebd Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:09 +0200 Subject: [PATCH 144/188] New translations app.json (Scottish Gaelic) --- Localization/StringsConvertor/input/gd_GB/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/gd_GB/app.json b/Localization/StringsConvertor/input/gd_GB/app.json index 236ad473..7053105d 100644 --- a/Localization/StringsConvertor/input/gd_GB/app.json +++ b/Localization/StringsConvertor/input/gd_GB/app.json @@ -492,6 +492,14 @@ "clear": "Falamhaich" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Na h-annsachdan agad" }, From 06ead9a0e1d61ceda9a2648616fc49f5805061c4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:10 +0200 Subject: [PATCH 145/188] New translations app.json (Kurmanji (Kurdish)) --- Localization/StringsConvertor/input/kmr_TR/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index ffa34577..59c78d0e 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -492,6 +492,14 @@ "clear": "Pak bike" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Bijarteyên te" }, From db6792f476a7bb6a798fb491dfd9eea4882b1336 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:10 +0200 Subject: [PATCH 146/188] New translations app.json (Swedish, Finland) --- Localization/StringsConvertor/input/sv_FI/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_FI/app.json b/Localization/StringsConvertor/input/sv_FI/app.json index 5bb7c8b7..769aadc5 100644 --- a/Localization/StringsConvertor/input/sv_FI/app.json +++ b/Localization/StringsConvertor/input/sv_FI/app.json @@ -492,6 +492,14 @@ "clear": "Tyhjennä" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Omat suosikit" }, From 513b681dfa034889b547e0d26cfbc1c80daf397c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:11 +0200 Subject: [PATCH 147/188] New translations app.json (Hindi) --- Localization/StringsConvertor/input/hi_IN/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/hi_IN/app.json b/Localization/StringsConvertor/input/hi_IN/app.json index a33a4f62..846a3f66 100644 --- a/Localization/StringsConvertor/input/hi_IN/app.json +++ b/Localization/StringsConvertor/input/hi_IN/app.json @@ -492,6 +492,14 @@ "clear": "Clear" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, From f5e790a9a77bf6a275622e4442058fbdb425b300 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:12 +0200 Subject: [PATCH 148/188] New translations app.json (Spanish, Argentina) --- Localization/StringsConvertor/input/es_AR/app.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/es_AR/app.json b/Localization/StringsConvertor/input/es_AR/app.json index c90fcb35..581ccd83 100644 --- a/Localization/StringsConvertor/input/es_AR/app.json +++ b/Localization/StringsConvertor/input/es_AR/app.json @@ -45,7 +45,7 @@ "message": "Por favor, habilitá el permiso de acceso a la biblioteca de fotos para guardar la imagen." }, "delete_post": { - "title": "¿Estás seguro que querés eliminar este mensaje?", + "title": "Eliminar mensaje", "message": "¿Estás seguro que querés eliminar este mensaje?" }, "clean_cache": { @@ -492,6 +492,14 @@ "clear": "Limpiar" } }, + "discovery": { + "tabs": { + "posts": "Mensajes", + "hashtags": "Etiquetas", + "news": "Novedades", + "for_you": "Para vos" + } + }, "favorite": { "title": "Tus favoritos" }, From 0c2d75c1c9f0461a5ee0a0ce9ed4fd0b927aebe8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:13 +0200 Subject: [PATCH 149/188] New translations app.json (Indonesian) --- Localization/StringsConvertor/input/id_ID/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/id_ID/app.json b/Localization/StringsConvertor/input/id_ID/app.json index 1de960d1..c6fe5610 100644 --- a/Localization/StringsConvertor/input/id_ID/app.json +++ b/Localization/StringsConvertor/input/id_ID/app.json @@ -492,6 +492,14 @@ "clear": "Hapus" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, From 7bba73e933c4a91dc309960788204b1d52854d1a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:14 +0200 Subject: [PATCH 150/188] New translations app.json (Portuguese, Brazilian) --- Localization/StringsConvertor/input/pt_BR/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_BR/app.json b/Localization/StringsConvertor/input/pt_BR/app.json index f0dc0ebf..548c5ada 100644 --- a/Localization/StringsConvertor/input/pt_BR/app.json +++ b/Localization/StringsConvertor/input/pt_BR/app.json @@ -492,6 +492,14 @@ "clear": "Clear" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, From 0e6a051b80b3dfb4eddcf6fa35d96d486580ae10 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:16 +0200 Subject: [PATCH 151/188] New translations app.json (Korean) --- Localization/StringsConvertor/input/ko_KR/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/ko_KR/app.json b/Localization/StringsConvertor/input/ko_KR/app.json index e75a2ae0..ab079573 100644 --- a/Localization/StringsConvertor/input/ko_KR/app.json +++ b/Localization/StringsConvertor/input/ko_KR/app.json @@ -492,6 +492,14 @@ "clear": "Clear" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, From 9f11b0445bed09629c032aa3036dc3fea24b6494 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:17 +0200 Subject: [PATCH 152/188] New translations app.json (Swedish) --- Localization/StringsConvertor/input/sv_SE/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/sv_SE/app.json b/Localization/StringsConvertor/input/sv_SE/app.json index d21203af..f18ce2dc 100644 --- a/Localization/StringsConvertor/input/sv_SE/app.json +++ b/Localization/StringsConvertor/input/sv_SE/app.json @@ -492,6 +492,14 @@ "clear": "Rensa" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, From 50cd3240cd9c8f77c721ec6a3a6dbb60fc4a4923 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:18 +0200 Subject: [PATCH 153/188] New translations app.json (Portuguese) --- Localization/StringsConvertor/input/pt_PT/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/pt_PT/app.json b/Localization/StringsConvertor/input/pt_PT/app.json index f0dc0ebf..548c5ada 100644 --- a/Localization/StringsConvertor/input/pt_PT/app.json +++ b/Localization/StringsConvertor/input/pt_PT/app.json @@ -492,6 +492,14 @@ "clear": "Clear" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, From a077b6540100c54bf511bc1cb463f6e313d6aaad Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:19 +0200 Subject: [PATCH 154/188] New translations app.json (Dutch) --- Localization/StringsConvertor/input/nl_NL/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/nl_NL/app.json b/Localization/StringsConvertor/input/nl_NL/app.json index 6d004c55..7a0e37a2 100644 --- a/Localization/StringsConvertor/input/nl_NL/app.json +++ b/Localization/StringsConvertor/input/nl_NL/app.json @@ -492,6 +492,14 @@ "clear": "Wissen" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Uw favorieten" }, From b6e7fd91f8bc61a7c107f2dd66b443be3f5a7f98 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:20 +0200 Subject: [PATCH 155/188] New translations app.json (Italian) --- Localization/StringsConvertor/input/it_IT/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/it_IT/app.json b/Localization/StringsConvertor/input/it_IT/app.json index 7d0ef92f..e81ea76a 100644 --- a/Localization/StringsConvertor/input/it_IT/app.json +++ b/Localization/StringsConvertor/input/it_IT/app.json @@ -492,6 +492,14 @@ "clear": "Cancella" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "I tuoi preferiti" }, From 848eb820a82b25338da5c289d89d8ab01eedb9b1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:21 +0200 Subject: [PATCH 156/188] New translations app.json (Japanese) --- Localization/StringsConvertor/input/ja_JP/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/ja_JP/app.json b/Localization/StringsConvertor/input/ja_JP/app.json index 5117c19f..fb16cf4b 100644 --- a/Localization/StringsConvertor/input/ja_JP/app.json +++ b/Localization/StringsConvertor/input/ja_JP/app.json @@ -492,6 +492,14 @@ "clear": "クリア" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "お気に入り" }, From b1c6f00ef901a42b94704ddd1699bafa6b689924 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:22 +0200 Subject: [PATCH 157/188] New translations Localizable.stringsdict (German) --- .../StringsConvertor/input/de_DE/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict index cd721862..20e8b615 100644 --- a/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/de_DE/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 Antwort other - %ld replies + %ld Antworten plural.count.vote From 9d00fbd343b77a6971132423e65ff2243646b394 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:23 +0200 Subject: [PATCH 158/188] New translations app.json (Basque) --- Localization/StringsConvertor/input/eu_ES/app.json | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/eu_ES/app.json b/Localization/StringsConvertor/input/eu_ES/app.json index 0e8b8e72..8547ae26 100644 --- a/Localization/StringsConvertor/input/eu_ES/app.json +++ b/Localization/StringsConvertor/input/eu_ES/app.json @@ -492,6 +492,14 @@ "clear": "Garbitu" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Zure gogokoak" }, @@ -502,8 +510,8 @@ }, "notification_description": { "followed_you": "zu jarraitzen hasi da", - "favorited_your_post": "erabiltzaileak zure bidalketa gogoko du", - "reblogged_your_post": "erabiltzaileak bultzada eman dio zure bidalketari", + "favorited_your_post": "(e)k zure bidalketa gogoko du", + "reblogged_your_post": "(e)k bultzada eman dio zure bidalketari", "mentioned_you": "erabiltzaileak aipatu zaitu", "request_to_follow_you": "erabiltzaileak zu jarraitzea eskatu du", "poll_has_ended": "inkesta amaitu da" From 2ec51140e4aff2ad449ae5c14cd59ff16e8b9a58 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:23 +0200 Subject: [PATCH 159/188] New translations app.json (Vietnamese) --- Localization/StringsConvertor/input/vi_VN/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/vi_VN/app.json b/Localization/StringsConvertor/input/vi_VN/app.json index 74a4bdfe..25cf47a7 100644 --- a/Localization/StringsConvertor/input/vi_VN/app.json +++ b/Localization/StringsConvertor/input/vi_VN/app.json @@ -492,6 +492,14 @@ "clear": "Xóa" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Lượt thích" }, From e51a829f972846e9ac5d701ab6646b5a7db97887 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:24 +0200 Subject: [PATCH 160/188] New translations app.json (Thai) --- Localization/StringsConvertor/input/th_TH/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index 3efdbb39..68621edb 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -492,6 +492,14 @@ "clear": "ล้าง" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "รายการโปรดของคุณ" }, From 598637fac6a9ac052464d050299572c158739201 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:25 +0200 Subject: [PATCH 161/188] New translations app.json (Chinese Simplified) --- Localization/StringsConvertor/input/zh_CN/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/zh_CN/app.json b/Localization/StringsConvertor/input/zh_CN/app.json index 9fb1bddd..898d24a1 100644 --- a/Localization/StringsConvertor/input/zh_CN/app.json +++ b/Localization/StringsConvertor/input/zh_CN/app.json @@ -492,6 +492,14 @@ "clear": "清除" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "你的喜欢" }, From 016076edfb96c884a9265cbdf8b30bfd4deb870a Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:26 +0200 Subject: [PATCH 162/188] New translations app.json (Russian) --- Localization/StringsConvertor/input/ru_RU/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/ru_RU/app.json b/Localization/StringsConvertor/input/ru_RU/app.json index 97281b0b..ca040eeb 100644 --- a/Localization/StringsConvertor/input/ru_RU/app.json +++ b/Localization/StringsConvertor/input/ru_RU/app.json @@ -492,6 +492,14 @@ "clear": "Очистить" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Ваше избранное" }, From e8d34f205c364ec2e4e03324676e55cfd7dff145 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 12:54:27 +0200 Subject: [PATCH 163/188] New translations app.json (Kabyle) --- Localization/StringsConvertor/input/kab_KAB/app.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Localization/StringsConvertor/input/kab_KAB/app.json b/Localization/StringsConvertor/input/kab_KAB/app.json index feb25700..08de0aef 100644 --- a/Localization/StringsConvertor/input/kab_KAB/app.json +++ b/Localization/StringsConvertor/input/kab_KAB/app.json @@ -492,6 +492,14 @@ "clear": "Sfeḍ" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Ismenyifen-ik·im" }, From 992787f7e7e7ddfc84d74717eb003ecfaa882421 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 15:00:50 +0200 Subject: [PATCH 164/188] New translations app.json (Catalan) --- Localization/StringsConvertor/input/ca_ES/app.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/ca_ES/app.json b/Localization/StringsConvertor/input/ca_ES/app.json index 3da2402d..c3484260 100644 --- a/Localization/StringsConvertor/input/ca_ES/app.json +++ b/Localization/StringsConvertor/input/ca_ES/app.json @@ -494,10 +494,10 @@ }, "discovery": { "tabs": { - "posts": "Posts", - "hashtags": "Hashtags", - "news": "News", - "for_you": "For You" + "posts": "Publicacions", + "hashtags": "Etiquetes", + "news": "Notícies", + "for_you": "Per a tu" } }, "favorite": { From 99722bc1a801af78c20c27b30ef183c465ead828 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 15:55:58 +0200 Subject: [PATCH 165/188] New translations app.json (Kurmanji (Kurdish)) --- Localization/StringsConvertor/input/kmr_TR/app.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/kmr_TR/app.json b/Localization/StringsConvertor/input/kmr_TR/app.json index 59c78d0e..61fb7033 100644 --- a/Localization/StringsConvertor/input/kmr_TR/app.json +++ b/Localization/StringsConvertor/input/kmr_TR/app.json @@ -494,10 +494,10 @@ }, "discovery": { "tabs": { - "posts": "Posts", - "hashtags": "Hashtags", - "news": "News", - "for_you": "For You" + "posts": "Şandî", + "hashtags": "Hashtag", + "news": "Nûçe", + "for_you": "Ji bo te" } }, "favorite": { From fffb88bc4a4059bf08b22132144944ec6fb226c4 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 18:32:47 +0200 Subject: [PATCH 166/188] New translations app.json (Italian) --- Localization/StringsConvertor/input/it_IT/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/it_IT/app.json b/Localization/StringsConvertor/input/it_IT/app.json index e81ea76a..cee51640 100644 --- a/Localization/StringsConvertor/input/it_IT/app.json +++ b/Localization/StringsConvertor/input/it_IT/app.json @@ -494,9 +494,9 @@ }, "discovery": { "tabs": { - "posts": "Posts", - "hashtags": "Hashtags", - "news": "News", + "posts": "Post", + "hashtags": "Hashtag", + "news": "Notizie", "for_you": "For You" } }, From ffa105599013f9c8a107d6e150ac052dc9b83a26 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 19:37:13 +0200 Subject: [PATCH 167/188] New translations app.json (Italian) --- Localization/StringsConvertor/input/it_IT/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/StringsConvertor/input/it_IT/app.json b/Localization/StringsConvertor/input/it_IT/app.json index cee51640..24044016 100644 --- a/Localization/StringsConvertor/input/it_IT/app.json +++ b/Localization/StringsConvertor/input/it_IT/app.json @@ -497,7 +497,7 @@ "posts": "Post", "hashtags": "Hashtag", "news": "Notizie", - "for_you": "For You" + "for_you": "Per Te" } }, "favorite": { From 67caa764a6dacbf5ca02a0fb9cc5be23afd49ce8 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 21:54:33 +0200 Subject: [PATCH 168/188] New translations app.json (Thai) --- Localization/StringsConvertor/input/th_TH/app.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/th_TH/app.json b/Localization/StringsConvertor/input/th_TH/app.json index 68621edb..b771f951 100644 --- a/Localization/StringsConvertor/input/th_TH/app.json +++ b/Localization/StringsConvertor/input/th_TH/app.json @@ -494,10 +494,10 @@ }, "discovery": { "tabs": { - "posts": "Posts", - "hashtags": "Hashtags", - "news": "News", - "for_you": "For You" + "posts": "โพสต์", + "hashtags": "แฮชแท็ก", + "news": "ข่าว", + "for_you": "สำหรับคุณ" } }, "favorite": { From 43a5562c601b8bc99b51f43646c73a042bcdfa94 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 22:53:38 +0200 Subject: [PATCH 169/188] New translations app.json (French) --- .../StringsConvertor/input/fr_FR/app.json | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Localization/StringsConvertor/input/fr_FR/app.json b/Localization/StringsConvertor/input/fr_FR/app.json index 56112082..642d2c37 100644 --- a/Localization/StringsConvertor/input/fr_FR/app.json +++ b/Localization/StringsConvertor/input/fr_FR/app.json @@ -130,7 +130,7 @@ "show_user_profile": "Montrer le profil de l’utilisateur·rice", "content_warning": "Avertissement de contenu", "media_content_warning": "Tapotez n’importe où pour révéler la publication", - "tap_to_reveal": "Tap to reveal", + "tap_to_reveal": "Appuyer pour afficher", "poll": { "vote": "Voter", "closed": "Fermé" @@ -143,9 +143,9 @@ "unfavorite": "Retirer des favoris", "menu": "Menu", "hide": "Cacher", - "show_image": "Show image", - "show_gif": "Show GIF", - "show_video_player": "Show video player", + "show_image": "Afficher l’image", + "show_gif": "Afficher le GIF", + "show_video_player": "Afficher le lecteur vidéo", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -447,10 +447,10 @@ } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", - "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "show_avatar_image": "Afficher l’avatar", + "edit_avatar_image": "Modifier l’avatar", + "show_banner_image": "Afficher l’image de la bannière", + "double_tap_to_open_the_list": "Appuyer deux fois pour ouvrir la liste" } }, "follower": { @@ -494,10 +494,10 @@ }, "discovery": { "tabs": { - "posts": "Posts", + "posts": "Messages", "hashtags": "Hashtags", - "news": "News", - "for_you": "For You" + "news": "Actualité", + "for_you": "Pour vous" } }, "favorite": { @@ -561,7 +561,7 @@ "disable_avatar_animation": "Désactiver les avatars animés", "disable_emoji_animation": "Désactiver les émojis animées", "using_default_browser": "Utiliser le navigateur par défaut pour ouvrir les liens", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "Ouvrir les liens dans Mastodon" }, "boring_zone": { "title": "La zone ennuyante", From dea70ec4b4a7974bbbe78e168ecf629fa6e80d97 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 22:53:39 +0200 Subject: [PATCH 170/188] New translations app.json (Arabic) --- Localization/StringsConvertor/input/ar_SA/app.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Localization/StringsConvertor/input/ar_SA/app.json b/Localization/StringsConvertor/input/ar_SA/app.json index a8831d65..d9712536 100644 --- a/Localization/StringsConvertor/input/ar_SA/app.json +++ b/Localization/StringsConvertor/input/ar_SA/app.json @@ -494,9 +494,9 @@ }, "discovery": { "tabs": { - "posts": "Posts", - "hashtags": "Hashtags", - "news": "News", + "posts": "المنشورات", + "hashtags": "الوسوم", + "news": "الأخبار", "for_you": "For You" } }, From a6b7a111dd88448588dc8759cec4e7a27955b594 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 15 Apr 2022 22:53:40 +0200 Subject: [PATCH 171/188] New translations Localizable.stringsdict (French) --- .../StringsConvertor/input/fr_FR/Localizable.stringsdict | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict index 93ee696f..5c2b1497 100644 --- a/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/fr_FR/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 réponse other - %ld replies + %ld réponses plural.count.vote From 9f79603ff09dae2cc2c5e8f090b2d1f62824ab1c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 16 Apr 2022 08:56:09 +0200 Subject: [PATCH 172/188] New translations app.json (Vietnamese) --- Localization/StringsConvertor/input/vi_VN/app.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Localization/StringsConvertor/input/vi_VN/app.json b/Localization/StringsConvertor/input/vi_VN/app.json index 25cf47a7..5aa16c95 100644 --- a/Localization/StringsConvertor/input/vi_VN/app.json +++ b/Localization/StringsConvertor/input/vi_VN/app.json @@ -494,10 +494,10 @@ }, "discovery": { "tabs": { - "posts": "Posts", - "hashtags": "Hashtags", - "news": "News", - "for_you": "For You" + "posts": "Tút", + "hashtags": "Hashtag", + "news": "Tin tức", + "for_you": "Dành cho bạn" } }, "favorite": { From 8a95563976579af9841fb97724ebca28bc045e8f Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 10:39:28 +0800 Subject: [PATCH 173/188] chore: use fixed height searchBar --- Mastodon/Scene/Search/Search/SearchViewController.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift index 7594eb47..982844f5 100644 --- a/Mastodon/Scene/Search/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/Search/SearchViewController.swift @@ -15,7 +15,7 @@ import MastodonLocalization final class HeightFixedSearchBar: UISearchBar { override var intrinsicContentSize: CGSize { - return CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) + return CGSize(width: CGFloat.greatestFiniteMagnitude, height: 36) } } @@ -179,14 +179,14 @@ extension SearchViewController: UISearchControllerDelegate { //extension SearchViewController: UICollectionViewDelegate { // func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): select item at: \(indexPath.debugDescription)") -// +// // defer { // collectionView.deselectItem(at: indexPath, animated: true) // } -// +// // guard let diffableDataSource = viewModel.diffableDataSource else { return } // guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } -// +// // switch item { // case .trend(let hashtag): // let viewModel = HashtagTimelineViewModel(context: context, hashtag: hashtag.name) From c57c3b430491b9a19c71c07a8da1788f250c7594 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 10:47:55 +0800 Subject: [PATCH 174/188] feat: make adaptive profile card layout on iPad when search tab display as compact column --- .../MastodonUI/View/Content/ProfileCardView.swift | 13 +++++++++++-- .../View/Control/ProfileStatusDashboardView.swift | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift index eb500b7c..95424b7e 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -78,6 +78,8 @@ public final class ProfileCardView: UIView { return metaText }() + let infoContainer = UIStackView() + let statusDashboardView = ProfileStatusDashboardView() let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() @@ -206,8 +208,8 @@ extension ProfileCardView { container.setCustomSpacing(16, after: bioMetaTextAdaptiveMarginContainerView) // infoContainer: H - [ statusDashboardView | (spacer) | relationshipActionButton ] - let infoContainer = UIStackView() infoContainer.axis = .horizontal + infoContainer.spacing = 8 let infoContainerAdaptiveMarginContainerView = AdaptiveMarginContainerView() infoContainerAdaptiveMarginContainerView.contentView = infoContainer infoContainerAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin @@ -225,7 +227,7 @@ extension ProfileCardView { relationshipActionButton.trailingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.trailingAnchor), relationshipActionButton.bottomAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.bottomAnchor), relationshipActionButton.widthAnchor.constraint(greaterThanOrEqualToConstant: ProfileCardView.friendshipActionButtonSize.width).priority(.required - 1), - relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.defaultHigh), + relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.required - 10), ]) let bottomPadding = UIView() @@ -243,6 +245,13 @@ extension ProfileCardView { viewModel.userInterfaceStyle = traitCollection.userInterfaceStyle } + + public override func layoutSubviews() { + super.layoutSubviews() + + let isCompactAdaptive = bounds.width < 350 + infoContainer.axis = isCompactAdaptive ? .vertical : .horizontal + } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift index 7d8e4fbc..320c1e90 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift @@ -55,7 +55,7 @@ extension ProfileStatusDashboardView { containerStackView.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh), ]) - let spacing: CGFloat = UIView.isZoomedMode ? 4 : 16 + let spacing: CGFloat = UIView.isZoomedMode ? 4 : 12 containerStackView.spacing = spacing containerStackView.axis = .horizontal containerStackView.distribution = .fillEqually From c4ab4f68c6a24b24e0009c4946500ff941c71862 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 15:33:29 +0800 Subject: [PATCH 175/188] fix: status sensitive toggle logic issue --- Mastodon.xcodeproj/project.pbxproj | 42 +++++------- .../xcschemes/xcschememanagement.plist | 14 ++-- .../xcshareddata/swiftpm/Package.resolved | 20 +++--- .../Provider/DataSourceFacade+Status.swift | 18 +----- ...er+NotificationTableViewCellDelegate.swift | 4 +- ...Provider+StatusTableViewCellDelegate.swift | 7 +- .../Content/MediaView+Configuration.swift | 8 +-- .../Content/StatusView+Configuration.swift | 15 ++--- .../TableviewCell/StatusTableViewCell.swift | 2 +- .../StatusThreadRootTableViewCell.swift | 2 +- MastodonSDK/Package.swift | 3 +- .../CoreData 3.xcdatamodel/contents | 7 +- .../Entity/Mastodon/Status.swift | 15 ++--- .../CoreDataStack/MastodonStatus.swift | 28 ++++++++ .../View/Content/StatusView+ViewModel.swift | 64 +++++++------------ .../MastodonUI/View/Content/StatusView.swift | 1 + .../View/Control/ActionToolbarContainer.swift | 2 +- .../Control/ProfileStatusDashboardView.swift | 6 +- 18 files changed, 111 insertions(+), 147 deletions(-) create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonStatus.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 54c68295..83cbb62a 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -115,9 +115,7 @@ DB0009A626AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; settings = {ATTRIBUTES = (no_codegen, ); }; }; DB0009A726AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; }; DB00CA972632DDB600A54956 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB00CA962632DDB600A54956 /* CommonOSLog */; }; - DB0140BD25C40D7500F9F3CF /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB0140BC25C40D7500F9F3CF /* CommonOSLog */; }; DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140CE25C42AEE00F9F3CF /* OSLog.swift */; }; - DB01E23326A98F0900C3965B /* MastodonMeta in Frameworks */ = {isa = PBXBuildFile; productRef = DB01E23226A98F0900C3965B /* MastodonMeta */; }; DB01E23526A98F0900C3965B /* MetaTextKit in Frameworks */ = {isa = PBXBuildFile; productRef = DB01E23426A98F0900C3965B /* MetaTextKit */; }; DB023D26279FFB0A005AC798 /* ShareActivityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB023D25279FFB0A005AC798 /* ShareActivityProvider.swift */; }; DB023D2827A0FABD005AC798 /* NotificationTableViewCellDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB023D2727A0FABD005AC798 /* NotificationTableViewCellDelegate.swift */; }; @@ -130,6 +128,8 @@ DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB029E94266A20430062874E /* MastodonAuthenticationController.swift */; }; DB02CDAB26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDAA26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift */; }; DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDBE2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift */; }; + DB02EA0B280D180D00E751C5 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = DB02EA0A280D180D00E751C5 /* KeychainAccess */; }; + DB02EA0D280D184B00E751C5 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB02EA0C280D184B00E751C5 /* CommonOSLog */; }; DB03A793272A7E5700EE37C5 /* SidebarListHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03A792272A7E5700EE37C5 /* SidebarListHeaderView.swift */; }; DB03A795272A981400EE37C5 /* ContentSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03A794272A981400EE37C5 /* ContentSplitViewController.swift */; }; DB03F7F32689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7F22689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift */; }; @@ -347,7 +347,6 @@ DB6804872637CD4C00430867 /* AppShared.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DB68047F2637CD4C00430867 /* AppShared.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; DB6804D12637CE4700430867 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6804D02637CE4700430867 /* UserDefaults.swift */; }; DB6804FD2637CFEC00430867 /* AppSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6804FC2637CFEC00430867 /* AppSecret.swift */; }; - DB6805102637D0F800430867 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = DB68050F2637D0F800430867 /* KeychainAccess */; }; DB68586425E619B700F0A850 /* NSKeyValueObservation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */; }; DB68A04A25E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68A04925E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift */; }; DB68A05D25E9055900CFDF14 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DB68A05C25E9055900CFDF14 /* Settings.bundle */; }; @@ -1372,7 +1371,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DB0140BD25C40D7500F9F3CF /* CommonOSLog in Frameworks */, DB9A487E2603456B008B817C /* UITextView+Placeholder in Frameworks */, 2D939AC825EE14620076FA61 /* CropViewController in Frameworks */, DBB525082611EAC0002F1F29 /* Tabman in Frameworks */, @@ -1382,10 +1380,10 @@ DBAC6483267D0B21007FE9FD /* DifferenceKit in Frameworks */, DB552D4F26BBD10C00E481F6 /* OrderedCollections in Frameworks */, 2D61336925C18A4F00CAE157 /* AlamofireNetworkActivityIndicator in Frameworks */, - DB01E23326A98F0900C3965B /* MastodonMeta in Frameworks */, DBAC64A1267E6D02007FE9FD /* Fuzi in Frameworks */, DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */, DBAC649E267DFE43007FE9FD /* DiffableDataSources in Frameworks */, + DB02EA0D280D184B00E751C5 /* CommonOSLog in Frameworks */, 2D5981BA25E4D7F8000FB903 /* ThirdPartyMailer in Frameworks */, 87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */, DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */, @@ -1415,7 +1413,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DB6805102637D0F800430867 /* KeychainAccess in Frameworks */, + DB02EA0B280D180D00E751C5 /* KeychainAccess in Frameworks */, EE93E8E8F9E0C39EAAEBD92F /* Pods_AppShared.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3303,7 +3301,6 @@ DB3D0FF225BAA61700EAA174 /* AlamofireImage */, 5D526FE125BE9AC400460CB9 /* MastodonSDK */, 2D61336825C18A4F00CAE157 /* AlamofireNetworkActivityIndicator */, - DB0140BC25C40D7500F9F3CF /* CommonOSLog */, 2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */, 2D939AC725EE14620076FA61 /* CropViewController */, DB9A487D2603456B008B817C /* UITextView+Placeholder */, @@ -3312,10 +3309,10 @@ DBAC649D267DFE43007FE9FD /* DiffableDataSources */, DBAC64A0267E6D02007FE9FD /* Fuzi */, DBF7A0FB26830C33004176A2 /* FPSIndicator */, - DB01E23226A98F0900C3965B /* MastodonMeta */, DB01E23426A98F0900C3965B /* MetaTextKit */, DB552D4E26BBD10C00E481F6 /* OrderedCollections */, DBA5A52E26F07ED800CACBAA /* PanModal */, + DB02EA0C280D184B00E751C5 /* CommonOSLog */, ); productName = Mastodon; productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */; @@ -3376,7 +3373,7 @@ ); name = AppShared; packageProductDependencies = ( - DB68050F2637D0F800430867 /* KeychainAccess */, + DB02EA0A280D180D00E751C5 /* KeychainAccess */, ); productName = AppShared; productReference = DB68047F2637CD4C00430867 /* AppShared.framework */; @@ -5421,7 +5418,7 @@ repositoryURL = "https://github.com/TwidereProject/MetaTextKit.git"; requirement = { kind = exactVersion; - version = 2.2.1; + version = 2.2.2; }; }; DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = { @@ -5539,21 +5536,21 @@ package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */; productName = CommonOSLog; }; - DB0140BC25C40D7500F9F3CF /* CommonOSLog */ = { - isa = XCSwiftPackageProductDependency; - package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */; - productName = CommonOSLog; - }; - DB01E23226A98F0900C3965B /* MastodonMeta */ = { - isa = XCSwiftPackageProductDependency; - package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */; - productName = MastodonMeta; - }; DB01E23426A98F0900C3965B /* MetaTextKit */ = { isa = XCSwiftPackageProductDependency; package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */; productName = MetaTextKit; }; + DB02EA0A280D180D00E751C5 /* KeychainAccess */ = { + isa = XCSwiftPackageProductDependency; + package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */; + productName = KeychainAccess; + }; + DB02EA0C280D184B00E751C5 /* CommonOSLog */ = { + isa = XCSwiftPackageProductDependency; + package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */; + productName = CommonOSLog; + }; DB0C946426A6FD4D0088FB11 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; @@ -5573,11 +5570,6 @@ package = DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */; productName = OrderedCollections; }; - DB68050F2637D0F800430867 /* KeychainAccess */ = { - isa = XCSwiftPackageProductDependency; - package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */; - productName = KeychainAccess; - }; DB6D9F41263527CE008423CD /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index e45da3c0..0d22a226 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -9,7 +9,7 @@ isShown orderHint - 4 + 5 CoreDataStack.xcscheme_^#shared#^_ @@ -19,7 +19,7 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 19 + 20 Mastodon - Release.xcscheme_^#shared#^_ @@ -29,12 +29,12 @@ Mastodon - Snapshot.xcscheme_^#shared#^_ orderHint - 2 + 3 Mastodon - ar.xcscheme orderHint - 3 + 4 Mastodon - ar.xcscheme_^#shared#^_ @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 33 + 26 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 32 + 23 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 31 + 24 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 11d45388..8dd69150 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/Alamofire/Alamofire.git", "state": { "branch": null, - "revision": "f82c23a8a7ef8dc1a49a8bfc6a96883e79121864", - "version": "5.5.0" + "revision": "354dda32d89fc8cd4f5c46487f64957d355f53d8", + "version": "5.6.1" } }, { @@ -96,8 +96,8 @@ "repositoryURL": "https://github.com/TwidereProject/MetaTextKit.git", "state": { "branch": null, - "revision": "3ea336d3de7938dc112084c596a646e697b0feee", - "version": "2.2.1" + "revision": "8074400b3819ef0395550082e6e8e960ef22e1f3", + "version": "2.2.2" } }, { @@ -105,8 +105,8 @@ "repositoryURL": "https://github.com/kean/Nuke.git", "state": { "branch": null, - "revision": "0db18dd34998cca18e9a28bcee136f84518007a0", - "version": "10.4.1" + "revision": "78fa963b8491fc520791d8c2a509f1b8593d8aae", + "version": "10.7.1" } }, { @@ -141,8 +141,8 @@ "repositoryURL": "https://github.com/SDWebImage/SDWebImage.git", "state": { "branch": null, - "revision": "2c53f531f1bedd253f55d85105409c28ed4a922c", - "version": "5.12.3" + "revision": "2e63d0061da449ad0ed130768d05dceb1496de44", + "version": "5.12.5" } }, { @@ -177,8 +177,8 @@ "repositoryURL": "https://github.com/siteline/SwiftUI-Introspect.git", "state": { "branch": null, - "revision": "2e09be8af614401bc9f87d40093ec19ce56ccaf2", - "version": "0.1.3" + "revision": "f2616860a41f9d9932da412a8978fec79c06fe24", + "version": "0.1.4" } }, { diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift index eab85e95..36ceb6dd 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift @@ -286,24 +286,8 @@ extension DataSourceFacade { try await dependency.context.managedObjectContext.perform { guard let _status = status.object(in: dependency.context.managedObjectContext) else { return } let status = _status.reblog ?? _status - - let allToggled = status.isContentSensitiveToggled && status.isMediaSensitiveToggled - - status.update(isContentSensitiveToggled: !allToggled) - status.update(isMediaSensitiveToggled: !allToggled) + status.update(isSensitiveToggled: !status.isSensitiveToggled) } } -// static func responseToToggleMediaSensitiveAction( -// dependency: NeedsDependency, -// status: ManagedObjectRecord -// ) async throws { -// try await dependency.context.managedObjectContext.perform { -// guard let _status = status.object(in: dependency.context.managedObjectContext) else { return } -// let status = _status.reblog ?? _status -// -// status.update(isMediaSensitiveToggled: !status.isMediaSensitiveToggled) -// } -// } - } diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift index 0924028f..f6e58673 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift @@ -135,7 +135,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Med let status = _status.reblog ?? _status return NotificationMediaTransitionContext( status: .init(objectID: status.objectID), - needsToggleMediaSensitive: status.isMediaSensitiveToggled ? !status.sensitive : status.sensitive + needsToggleMediaSensitive: status.isSensitiveToggled ? !status.sensitive : status.sensitive ) } @@ -187,7 +187,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Med let status = _status.reblog ?? _status return NotificationMediaTransitionContext( status: .init(objectID: status.objectID), - needsToggleMediaSensitive: status.isMediaSensitiveToggled ? !status.sensitive : status.sensitive + needsToggleMediaSensitive: status.isMediaSensitive ? !status.isSensitiveToggled : false ) } diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift index d14b5c34..9e5838e7 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift @@ -143,12 +143,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & MediaPrev return } - let managedObjectContext = self.context.managedObjectContext - let needsToggleMediaSensitive: Bool = try await managedObjectContext.perform { - guard let _status = status.object(in: managedObjectContext) else { return false } - let status = _status.reblog ?? _status - return status.isMediaSensitiveToggled ? !status.sensitive : status.sensitive - } + let needsToggleMediaSensitive = await !statusView.viewModel.isMediaReveal guard !needsToggleMediaSensitive else { try await DataSourceFacade.responseToToggleSensitiveAction( diff --git a/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift b/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift index cba1fcf6..02f9ad5a 100644 --- a/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift +++ b/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift @@ -62,14 +62,14 @@ extension MediaView { { let placeholder = UIImage.placeholder(color: .systemGray6) let request = URLRequest(url: url) - ImageDownloader.default.download(request) { response in + ImageDownloader.default.download(request, completion: { response in switch response.result { case .success(let image): configuration.previewImage = image - case .failure(let error): + case .failure: configuration.previewImage = placeholder } - } + }) } if let assetURL = configuration.assetURL, @@ -84,7 +84,7 @@ extension MediaView { .store(in: &configuration.blurhashImageDisposeBag) } - configuration.isReveal = status.sensitive ? status.isMediaSensitiveToggled : true + configuration.isReveal = status.isMediaSensitive ? status.isSensitiveToggled : true return configuration } diff --git a/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift b/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift index 1a90c69a..ab4fea1a 100644 --- a/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift +++ b/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift @@ -156,7 +156,6 @@ extension StatusView { .map { _ in author.avatarImageURL() } .assign(to: \.authorAvatarImageURL, on: viewModel) .store(in: &disposeBag) - // author name Publishers.CombineLatest( author.publisher(for: \.displayName), @@ -268,25 +267,19 @@ extension StatusView { .assign(to: \.visibility, on: viewModel) .store(in: &disposeBag) // sensitive - status.publisher(for: \.isContentSensitiveToggled) - .assign(to: \.isContentSensitiveToggled, on: viewModel) + viewModel.isContentSensitive = status.isContentSensitive + status.publisher(for: \.isSensitiveToggled) + .assign(to: \.isSensitiveToggled, on: viewModel) .store(in: &disposeBag) - - -// viewModel.source = status.source } private func configureMedia(status: Status) { let status = status.reblog ?? status - viewModel.isMediaSensitive = status.sensitive && !status.attachments.isEmpty // some servers set media sensitive even empty attachments + viewModel.isMediaSensitive = status.isMediaSensitive let configurations = MediaView.configuration(status: status) viewModel.mediaViewConfigurations = configurations - - status.publisher(for: \.isMediaSensitiveToggled) - .assign(to: \.isMediaSensitiveToggled, on: viewModel) - .store(in: &disposeBag) } private func configurePoll(status: Status) { diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift index a1033f05..a3315211 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift @@ -61,7 +61,7 @@ extension StatusTableViewCell { statusView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), containerViewLeadingLayoutConstraint, containerViewTrailingLayoutConstraint, - statusView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + contentView.bottomAnchor.constraint(equalTo: statusView.bottomAnchor, constant: 10), ]) statusView.setup(style: .inline) updateContainerViewMarginConstraints() diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift index e27cc2dd..11517580 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift @@ -112,7 +112,7 @@ extension StatusThreadRootTableViewCell { statusView.statusMetricView ] - if !statusView.viewModel.isSensitive { + if !statusView.viewModel.isMediaSensitive { elements.removeAll(where: { $0 === statusView.contentSensitiveeToggleButton }) } diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index dd562f14..ed4a13d5 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -32,7 +32,7 @@ let package = Package( .package(url: "https://github.com/apple/swift-nio.git", from: "1.0.0"), .package(url: "https://github.com/kean/Nuke.git", from: "10.3.1"), .package(url: "https://github.com/Flipboard/FLAnimatedImage.git", from: "1.0.0"), - .package(url: "https://github.com/TwidereProject/MetaTextKit.git", .exact("2.2.1")), + .package(url: "https://github.com/TwidereProject/MetaTextKit.git", .exact("2.2.2")), .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.4.0"), .package(url: "https://github.com/Alamofire/AlamofireImage.git", from: "4.1.0"), .package(name: "NukeFLAnimatedImagePlugin", url: "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git", from: "8.0.0"), @@ -94,7 +94,6 @@ let package = Package( .product(name: "Alamofire", package: "Alamofire"), .product(name: "AlamofireImage", package: "AlamofireImage"), .product(name: "MetaTextKit", package: "MetaTextKit"), - .product(name: "MastodonMeta", package: "MetaTextKit"), .product(name: "FLAnimatedImage", package: "FLAnimatedImage"), ] ), diff --git a/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 3.xcdatamodel/contents b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 3.xcdatamodel/contents index a6f0ee0c..16a1c7c8 100644 --- a/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 3.xcdatamodel/contents +++ b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 3.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -185,8 +185,7 @@ - - + @@ -262,7 +261,7 @@ - + diff --git a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift index d17d1c61..0c729191 100644 --- a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift +++ b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift @@ -42,9 +42,7 @@ public final class Status: NSManagedObject { @NSManaged public private(set) var spoilerText: String? // sourcery: autoUpdatableObject - @NSManaged public private(set) var isContentSensitiveToggled: Bool - // sourcery: autoUpdatableObject - @NSManaged public private(set) var isMediaSensitiveToggled: Bool + @NSManaged public private(set) var isSensitiveToggled: Bool @NSManaged public private(set) var application: Application? @@ -432,14 +430,9 @@ extension Status: AutoUpdatableObject { self.spoilerText = spoilerText } } - public func update(isContentSensitiveToggled: Bool) { - if self.isContentSensitiveToggled != isContentSensitiveToggled { - self.isContentSensitiveToggled = isContentSensitiveToggled - } - } - public func update(isMediaSensitiveToggled: Bool) { - if self.isMediaSensitiveToggled != isMediaSensitiveToggled { - self.isMediaSensitiveToggled = isMediaSensitiveToggled + public func update(isSensitiveToggled: Bool) { + if self.isSensitiveToggled != isSensitiveToggled { + self.isSensitiveToggled = isSensitiveToggled } } public func update(reblogsCount: Int64) { diff --git a/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonStatus.swift b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonStatus.swift new file mode 100644 index 00000000..b7d33712 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonStatus.swift @@ -0,0 +1,28 @@ +// +// MastodonStatus.swift +// +// +// Created by MainasuK on 2022-4-18. +// + +import Foundation +import CoreDataStack + +extension Status { + + // mark content sensitive when status contains spoilerText + public var isContentSensitive: Bool { + if let spoilerText = spoilerText, !spoilerText.isEmpty { + return true + } else { + return false + } + } + + // mark media sensitive when `isContentSensitive` or media marked sensitive + public var isMediaSensitive: Bool { + // some servers set media sensitive even empty attachments + return isContentSensitive || (sensitive && !attachments.isEmpty) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift index 67cefa47..ea80a61d 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift @@ -74,11 +74,9 @@ extension StatusView { // Sensitive @Published public var isContentSensitive: Bool = false - @Published public var isContentSensitiveToggled: Bool = false @Published public var isMediaSensitive: Bool = false - @Published public var isMediaSensitiveToggled: Bool = false - - @Published public var isSensitive: Bool = false // isContentSensitive || isMediaSensitive + @Published public var isSensitiveToggled = false + @Published public var isContentReveal: Bool = true @Published public var isMediaReveal: Bool = true @@ -130,9 +128,8 @@ extension StatusView { authorAvatarImageURL = nil isContentSensitive = false - isContentSensitiveToggled = false isMediaSensitive = false - isMediaSensitiveToggled = false + isSensitiveToggled = false activeFilters = [] filterContext = nil @@ -161,28 +158,18 @@ extension StatusView { $spoilerContent .map { $0 != nil } .assign(to: &$isContentSensitive) - // isSensitive - Publishers.CombineLatest( + // isReveal + Publishers.CombineLatest3( $isContentSensitive, - $isMediaSensitive - ) - .map { $0 || $1 } - .assign(to: &$isSensitive) - // $isContentReveal - Publishers.CombineLatest( - $isContentSensitive, - $isContentSensitiveToggled - ) - .map { $0 ? $1 : true } - .assign(to: &$isContentReveal) - // $isMediaReveal - Publishers.CombineLatest( $isMediaSensitive, - $isMediaSensitiveToggled + $isSensitiveToggled ) - .map { $1 ? !$0 : $0 } - .map { !$0 } - .assign(to: &$isMediaReveal) + .sink { [weak self] isContentSensitive, isMediaSensitive, isSensitiveToggled in + guard let self = self else { return } + self.isContentReveal = isContentSensitive ? isSensitiveToggled : true + self.isMediaReveal = isMediaSensitive ? isSensitiveToggled : true + } + .store(in: &disposeBag) } } } @@ -326,29 +313,22 @@ extension StatusView.ViewModel { } .store(in: &disposeBag) - $isSensitive + $isMediaSensitive .sink { isSensitive in guard isSensitive else { return } statusView.setContentSensitiveeToggleButtonDisplay() } .store(in: &disposeBag) - // There are 2 conditions: - // 1. The content may non-sensitive with sensitive media - // 2. The content and media both senstivie - Publishers.CombineLatest( - $isContentSensitiveToggled, - $isMediaSensitiveToggled - ) - .map { $0 || $1 } - .sink { isSensitiveToggled in - // The button indicator go-to state for button action direction - // eye: when media is hidden - // eye-slash: when media display - let image = isSensitiveToggled ? UIImage(systemName: "eye.slash.fill") : UIImage(systemName: "eye.fill") - statusView.contentSensitiveeToggleButton.setImage(image, for: .normal) - } - .store(in: &disposeBag) + $isSensitiveToggled + .sink { isSensitiveToggled in + // The button indicator go-to state for button action direction + // eye: when media is hidden + // eye-slash: when media display + let image = isSensitiveToggled ? UIImage(systemName: "eye.slash.fill") : UIImage(systemName: "eye.fill") + statusView.contentSensitiveeToggleButton.setImage(image, for: .normal) + } + .store(in: &disposeBag) } private func bindMedia(statusView: StatusView) { diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index eb3a6935..7b96fe0b 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -508,6 +508,7 @@ extension StatusView.Style { // status content statusView.contentContainer.addArrangedSubview(statusView.contentMetaText.textView) + statusView.containerStackView.setCustomSpacing(16, after: statusView.contentMetaText.textView) statusView.spoilerOverlayView.translatesAutoresizingMaskIntoConstraints = false statusView.containerStackView.addSubview(statusView.spoilerOverlayView) diff --git a/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift index 449254d2..c3a9b96f 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift @@ -114,7 +114,7 @@ extension ActionToolbarContainer { container.addArrangedSubview(favoriteButton) container.addArrangedSubview(shareButton) NSLayoutConstraint.activate([ - replyButton.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh), + replyButton.heightAnchor.constraint(equalToConstant: 36).priority(.defaultHigh), replyButton.heightAnchor.constraint(equalTo: reblogButton.heightAnchor).priority(.defaultHigh), replyButton.heightAnchor.constraint(equalTo: favoriteButton.heightAnchor).priority(.defaultHigh), replyButton.heightAnchor.constraint(equalTo: shareButton.heightAnchor).priority(.defaultHigh), diff --git a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift index 320c1e90..a45e8ef6 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift @@ -75,9 +75,9 @@ extension ProfileStatusDashboardView { tapGestureRecognizer.addTarget(self, action: #selector(ProfileStatusDashboardView.tapGestureRecognizerHandler(_:))) meterView.addGestureRecognizer(tapGestureRecognizer) } - - followingDashboardMeterView.accessibilityHint = "Double tap to open the list" // TODO: i18n - followersDashboardMeterView.accessibilityHint = "Double tap to open the list" + + followingDashboardMeterView.accessibilityHint = L10n.Scene.Profile.Accessibility.doubleTapToOpenTheList + followersDashboardMeterView.accessibilityHint = L10n.Scene.Profile.Accessibility.doubleTapToOpenTheList } } From 41e1b75c62248c64349513bb969ab31462ec78db Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 16:15:24 +0800 Subject: [PATCH 176/188] feat: add sensitive hint label for status media --- Localization/app.json | 1 + .../NotificationTimelineViewController.swift | 23 ++++++ .../Container/MediaGridContainerView.swift | 66 +++++------------ .../View/Content/StatusView+ViewModel.swift | 1 + .../Control/ContentWarningOverlayView.swift | 70 +++++-------------- 5 files changed, 61 insertions(+), 100 deletions(-) diff --git a/Localization/app.json b/Localization/app.json index 548c5ada..6c4aae7a 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -129,6 +129,7 @@ "show_post": "Show Post", "show_user_profile": "Show user profile", "content_warning": "Content Warning", + "sensitive_content": "Sensitive Content", "media_content_warning": "Tap anywhere to reveal", "tap_to_reveal": "Tap to reveal", "poll": { diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift index bdb4d05c..16130251 100644 --- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift +++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift @@ -39,6 +39,8 @@ final class NotificationTimelineViewController: UIViewController, NeedsDependenc return tableView }() + let cellFrameCache = NSCache() + deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } @@ -122,6 +124,16 @@ extension NotificationTimelineViewController { } +// MARK: - CellFrameCacheContainer +extension NotificationTimelineViewController: CellFrameCacheContainer { + func keyForCache(tableView: UITableView, indexPath: IndexPath) -> NSNumber? { + guard let diffableDataSource = viewModel.diffableDataSource else { return nil } + guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return nil } + let key = NSNumber(value: item.hashValue) + return key + } +} + extension NotificationTimelineViewController { @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { @@ -162,6 +174,13 @@ extension NotificationTimelineViewController: UITableViewDelegate, AutoGenerateT // sourcery:end + func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { + guard let frame = retrieveCellFrame(tableView: tableView, indexPath: indexPath) else { + return 300 + } + return ceil(frame.height) + } + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return @@ -172,6 +191,10 @@ extension NotificationTimelineViewController: UITableViewDelegate, AutoGenerateT await viewModel.loadMore(item: item) } } + + func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { + cacheCellFrame(tableView: tableView, didEndDisplaying: cell, forRowAt: indexPath) + } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Container/MediaGridContainerView.swift b/MastodonSDK/Sources/MastodonUI/View/Container/MediaGridContainerView.swift index cb9c53f3..e3359fb5 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Container/MediaGridContainerView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Container/MediaGridContainerView.swift @@ -48,22 +48,7 @@ public final class MediaGridContainerView: UIView { return mediaViews }() - -// let sensitiveToggleButtonBlurVisualEffectView: UIVisualEffectView = { -// let visualEffectView = UIVisualEffectView(effect: ContentWarningOverlayView.blurVisualEffect) -// visualEffectView.layer.masksToBounds = true -// visualEffectView.layer.cornerRadius = MediaGridContainerView.sensitiveToggleButtonSize.width / 2 -// visualEffectView.layer.cornerCurve = .continuous -// return visualEffectView -// }() -// let sensitiveToggleButtonVibrancyVisualEffectView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: ContentWarningOverlayView.blurVisualEffect)) -// let sensitiveToggleButton: HitTestExpandedButton = { -// let button = HitTestExpandedButton(type: .system) -// button.contentEdgeInsets = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4) -// button.imageView?.contentMode = .scaleAspectFit -// button.setImage(UIImage(systemName: "eye.slash.fill"), for: .normal) -// return button -// }() + let contentWarningOverlay = ContentWarningOverlayView() public override init(frame: CGRect) { super.init(frame: frame) @@ -86,7 +71,8 @@ public final class MediaGridContainerView: UIView { extension MediaGridContainerView { private func _init() { -// sensitiveToggleButton.addTarget(self, action: #selector(MediaGridContainerView.sensitiveToggleButtonDidPressed(_:)), for: .touchUpInside) + contentWarningOverlay.isUserInteractionEnabled = false + contentWarningOverlay.isHidden = true } } @@ -112,8 +98,8 @@ extension MediaGridContainerView { let mediaView = _mediaViews[0] layout.layout(in: self, mediaView: mediaView) -// layoutSensitiveToggleButton() -// bringSubviewToFront(sensitiveToggleButtonBlurVisualEffectView) + layoutContentWarningOverlay() + bringSubviewToFront(contentWarningOverlay) return mediaView } @@ -124,8 +110,8 @@ extension MediaGridContainerView { let mediaViews = Array(_mediaViews[0.. Date: Mon, 18 Apr 2022 16:56:29 +0800 Subject: [PATCH 177/188] fix: pick sever search bar accessible a11y issue --- .../xcshareddata/xcschemes/Mastodon.xcscheme | 8 -------- .../View/PickServerServerSectionTableHeaderView.swift | 6 +++--- .../MastodonUI/View/TableViewCell/NewsTableViewCell.swift | 5 +++++ 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme index 048ce3cf..488d5a2d 100644 --- a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme +++ b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme @@ -73,7 +73,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - enableAddressSanitizer = "YES" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -90,13 +89,6 @@ ReferencedContainer = "container:Mastodon.xcodeproj"> - - - - Int { guard let diffableDataSource = diffableDataSource else { return 0 } - return diffableDataSource.snapshot().itemIdentifiers.count + return diffableDataSource.snapshot().itemIdentifiers.count + 1 } override func accessibilityElement(at index: Int) -> Any? { - guard let item = collectionView.cellForItem(at: IndexPath(item: index, section: 0)) else { return nil } - return item + if let item = collectionView.cellForItem(at: IndexPath(item: index, section: 0)) { return item } + return searchTextField } } diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift index 3515000f..f0b2aec8 100644 --- a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift @@ -51,6 +51,11 @@ extension NewsTableViewCell { separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), ]) + + isAccessibilityElement = true + accessibilityElements = [ + newsView + ] } } From 03af68924ce36ed4e198025602f54f627ca1d375 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 17:14:49 +0800 Subject: [PATCH 178/188] feat: add favicon for NewsView --- .../xcshareddata/swiftpm/Package.resolved | 18 ++++++++++++ MastodonSDK/Package.swift | 4 ++- .../View/Content/NewsView+Configuration.swift | 19 ++++++++++++ .../MastodonUI/View/Content/NewsView.swift | 29 +++++++++++++++++-- 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 8dd69150..53f6a3a4 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -55,6 +55,15 @@ "version": "1.2.0" } }, + { + "package": "FaviconFinder", + "repositoryURL": "https://github.com/will-lumley/FaviconFinder.git", + "state": { + "branch": null, + "revision": "1f74844f77f79b95c0bb0130b3a87d4f340e6d3a", + "version": "3.3.0" + } + }, { "package": "FLAnimatedImage", "repositoryURL": "https://github.com/Flipboard/FLAnimatedImage.git", @@ -172,6 +181,15 @@ "version": "1.0.0" } }, + { + "package": "SwiftSoup", + "repositoryURL": "https://github.com/scinfu/SwiftSoup.git", + "state": { + "branch": null, + "revision": "41e7c263fb8c277e980ebcb9b0b5f6031d3d4886", + "version": "2.4.2" + } + }, { "package": "Introspect", "repositoryURL": "https://github.com/siteline/SwiftUI-Introspect.git", diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index ed4a13d5..8b007c2a 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -37,7 +37,8 @@ let package = Package( .package(url: "https://github.com/Alamofire/AlamofireImage.git", from: "4.1.0"), .package(name: "NukeFLAnimatedImagePlugin", url: "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git", from: "8.0.0"), .package(name: "UITextView+Placeholder", url: "https://github.com/MainasuK/UITextView-Placeholder.git", from: "1.4.1"), - .package(name: "Introspect", url: "https://github.com/siteline/SwiftUI-Introspect.git", from: "0.1.3") + .package(name: "Introspect", url: "https://github.com/siteline/SwiftUI-Introspect.git", from: "0.1.3"), + .package(name: "FaviconFinder", url: "https://github.com/will-lumley/FaviconFinder.git", from: "3.2.2"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -95,6 +96,7 @@ let package = Package( .product(name: "AlamofireImage", package: "AlamofireImage"), .product(name: "MetaTextKit", package: "MetaTextKit"), .product(name: "FLAnimatedImage", package: "FLAnimatedImage"), + .product(name: "FaviconFinder", package: "FaviconFinder"), ] ), .testTarget( diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift index e045eafe..397982aa 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift @@ -9,9 +9,28 @@ import UIKit import MastodonSDK import MastodonLocalization import AlamofireImage +import FaviconFinder extension NewsView { public func configure(link: Mastodon.Entity.Link) { + let faviconPlaceholder = UIImage(systemName: "network") + providerFaviconImageView.image = faviconPlaceholder + if let url = URL(string: link.url) { + let token = providerFaviconImageView.tag + FaviconFinder(url: url).downloadFavicon { [weak self] result in + guard let self = self else { return } + switch result { + case .success(let favicon): + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + guard self.providerFaviconImageView.tag == token else { return } + self.providerFaviconImageView.image = favicon.image + } + case .failure: + break + } + } + } providerNameLabel.text = link.providerName headlineLabel.text = link.title footnoteLabel.text = L10n.Plural.peopleTalking(link.talkingPeopleCount ?? 0) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift index ee9506a9..6d4cf3fd 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift @@ -12,6 +12,15 @@ public final class NewsView: UIView { let container = UIStackView() + let providerFaviconImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + imageView.layer.masksToBounds = true + imageView.layer.cornerRadius = 2 + imageView.layer.cornerCurve = .continuous + return imageView + }() + let providerNameLabel: UILabel = { let label = UILabel() label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .semibold)) @@ -37,6 +46,7 @@ public final class NewsView: UIView { let imageView = MediaView() public func prepareForReuse() { + providerFaviconImageView.tag = (0.. Date: Mon, 18 Apr 2022 17:18:24 +0800 Subject: [PATCH 179/188] fix: extend corner radius for ProfileCard avatar background --- .../Sources/MastodonUI/View/Content/ProfileCardView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift index 95424b7e..ddc9afe4 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -181,7 +181,7 @@ extension ProfileCardView { avatarButtonBackgroundView.layer.masksToBounds = true avatarButtonBackgroundView.layer.cornerCurve = .continuous - avatarButtonBackgroundView.layer.cornerRadius = 12 + avatarButtonBackgroundView.layer.cornerRadius = 12 + 1 avatarButtonBackgroundView.translatesAutoresizingMaskIntoConstraints = false authorContainer.insertSubview(avatarButtonBackgroundView, belowSubview: avatarButton) NSLayoutConstraint.activate([ From 64640edd2b3ef0c466be5053418f0c4fdd1e2653 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 17:44:19 +0800 Subject: [PATCH 180/188] feat: add ProfileCardView a11y supports --- .../Content/ProfileCardView+ViewModel.swift | 26 +++++++++++++++++++ .../View/Content/ProfileCardView.swift | 14 +++++++--- .../ProfileCardTableViewCell.swift | 6 +++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift index 99eb27a5..5b6c4c59 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift @@ -42,6 +42,8 @@ extension ProfileCardView { @Published public var isBlocking = false @Published public var isBlockedBy = false + @Published public var groupedAccessibilityLabel = "" + init() { backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor Publishers.CombineLatest( @@ -75,6 +77,7 @@ extension ProfileCardView.ViewModel { bindBio(view: view) bindRelationship(view: view) bindDashboard(view: view) + bindAccessibility(view: view) } private func bindAppearacne(view: ProfileCardView) { @@ -185,4 +188,27 @@ extension ProfileCardView.ViewModel { } .store(in: &disposeBag) } + + private func bindAccessibility(view: ProfileCardView) { + let authorAccessibilityLabel = Publishers.CombineLatest( + $authorName, + $bioContent + ) + .map { authorName, bioContent -> String? in + var strings: [String?] = [] + strings.append(authorName?.string) + strings.append(bioContent?.string) + return strings.compactMap { $0 }.joined(separator: ", ") + } + + authorAccessibilityLabel + .map { $0 ?? "" } + .assign(to: &$groupedAccessibilityLabel) + + $groupedAccessibilityLabel + .sink { accessibilityLabel in + view.accessibilityLabel = accessibilityLabel + } + .store(in: &disposeBag) + } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift index ddc9afe4..16351ebe 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -204,6 +204,8 @@ extension ProfileCardView { let bioMetaTextAdaptiveMarginContainerView = AdaptiveMarginContainerView() bioMetaTextAdaptiveMarginContainerView.contentView = bioMetaText.textView bioMetaTextAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin + bioMetaText.textView.setContentHuggingPriority(.required - 1, for: .vertical) + bioMetaText.textView.setContentCompressionResistancePriority(.required - 1, for: .vertical) container.addArrangedSubview(bioMetaTextAdaptiveMarginContainerView) container.setCustomSpacing(16, after: bioMetaTextAdaptiveMarginContainerView) @@ -218,6 +220,7 @@ extension ProfileCardView { infoContainer.addArrangedSubview(UIView()) let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() infoContainer.addArrangedSubview(relationshipActionButtonShadowContainer) + updateInfoContainerLayout() relationshipActionButton.translatesAutoresizingMaskIntoConstraints = false relationshipActionButtonShadowContainer.addSubview(relationshipActionButton) @@ -227,7 +230,7 @@ extension ProfileCardView { relationshipActionButton.trailingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.trailingAnchor), relationshipActionButton.bottomAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.bottomAnchor), relationshipActionButton.widthAnchor.constraint(greaterThanOrEqualToConstant: ProfileCardView.friendshipActionButtonSize.width).priority(.required - 1), - relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.required - 10), + relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.required - 2), ]) let bottomPadding = UIView() @@ -247,12 +250,17 @@ extension ProfileCardView { } public override func layoutSubviews() { + updateInfoContainerLayout() super.layoutSubviews() - + } + +} + +extension ProfileCardView { + private func updateInfoContainerLayout() { let isCompactAdaptive = bounds.width < 350 infoContainer.axis = isCompactAdaptive ? .vertical : .horizontal } - } extension ProfileCardView { diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift index d3c8f223..5961ad10 100644 --- a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift @@ -70,6 +70,12 @@ extension ProfileCardTableViewCell { ]) profileCardView.delegate = self + + profileCardView.isAccessibilityElement = true + accessibilityElements = [ + profileCardView, + profileCardView.relationshipActionButton + ] } } From 555d36ca0c2f498046a3fa87e58c63f86cda7748 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 18 Apr 2022 11:48:42 +0200 Subject: [PATCH 181/188] New translations app.json (Chinese Simplified) --- Localization/StringsConvertor/input/zh_CN/app.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Localization/StringsConvertor/input/zh_CN/app.json b/Localization/StringsConvertor/input/zh_CN/app.json index 898d24a1..db871d5a 100644 --- a/Localization/StringsConvertor/input/zh_CN/app.json +++ b/Localization/StringsConvertor/input/zh_CN/app.json @@ -449,7 +449,7 @@ "accessibility": { "show_avatar_image": "显示头像", "edit_avatar_image": "编辑头像", - "show_banner_image": "Show banner image", + "show_banner_image": "显示顶部横幅图片", "double_tap_to_open_the_list": "双击打开列表" } }, @@ -494,10 +494,10 @@ }, "discovery": { "tabs": { - "posts": "Posts", - "hashtags": "Hashtags", - "news": "News", - "for_you": "For You" + "posts": "帖子", + "hashtags": "话题", + "news": "新闻", + "for_you": "为你推荐" } }, "favorite": { From 5133ba3fcb34d85591121bbf4b7b0474654ae39f Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 17:53:52 +0800 Subject: [PATCH 182/188] chore: update i18n resources --- .../Generated/Strings.swift | 12 ++++ .../Resources/ar.lproj/Localizable.strings | 4 ++ .../ar.lproj/Localizable.stringsdict | 60 +++++++++---------- .../Resources/ca.lproj/Localizable.strings | 46 +++++++------- .../Resources/de.lproj/Localizable.strings | 24 ++++---- .../de.lproj/Localizable.stringsdict | 4 +- .../Resources/en.lproj/Localizable.strings | 4 ++ .../es-419.lproj/Localizable.strings | 6 +- .../Resources/es.lproj/Localizable.strings | 4 ++ .../Resources/eu-ES.lproj/Localizable.strings | 28 +++++---- .../eu-ES.lproj/Localizable.stringsdict | 4 +- .../Resources/fr.lproj/Localizable.strings | 22 ++++--- .../fr.lproj/Localizable.stringsdict | 4 +- .../Resources/gd-GB.lproj/Localizable.strings | 4 ++ .../Resources/ja.lproj/Localizable.strings | 4 ++ .../Resources/kab.lproj/Localizable.strings | 4 ++ .../Resources/ku.lproj/Localizable.strings | 4 ++ .../Resources/nl.lproj/Localizable.strings | 4 ++ .../Resources/ru.lproj/Localizable.strings | 32 +++++----- .../Resources/sv_FI.lproj/Localizable.strings | 4 ++ .../Resources/th.lproj/Localizable.strings | 24 ++++---- .../th.lproj/Localizable.stringsdict | 2 +- .../Resources/vi.lproj/Localizable.strings | 12 ++-- .../zh-Hans.lproj/Localizable.strings | 24 ++++---- .../zh-Hans.lproj/Localizable.stringsdict | 2 +- 25 files changed, 212 insertions(+), 130 deletions(-) diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index 15d786ef..f2bec6b0 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -543,6 +543,18 @@ public enum L10n { public static let title = L10n.tr("Localizable", "Scene.ConfirmEmail.OpenEmailApp.Title") } } + public enum Discovery { + public enum Tabs { + /// For You + public static let forYou = L10n.tr("Localizable", "Scene.Discovery.Tabs.ForYou") + /// Hashtags + public static let hashtags = L10n.tr("Localizable", "Scene.Discovery.Tabs.Hashtags") + /// News + public static let news = L10n.tr("Localizable", "Scene.Discovery.Tabs.News") + /// Posts + public static let posts = L10n.tr("Localizable", "Scene.Discovery.Tabs.Posts") + } + } public enum Favorite { /// Your Favorites public static let title = L10n.tr("Localizable", "Scene.Favorite.Title") diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings index f26554fe..bf6ab09e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings @@ -201,6 +201,10 @@ "Scene.ConfirmEmail.Subtitle" = "لقد أرسلنا للتو بريد إلكتروني إلى %@، انقر على الرابط لتأكيد حسابك."; "Scene.ConfirmEmail.Title" = "شيءٌ أخير."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "الوسوم"; +"Scene.Discovery.Tabs.News" = "الأخبار"; +"Scene.Discovery.Tabs.Posts" = "المنشورات"; "Scene.Favorite.Title" = "مُفضَّلَتُك"; "Scene.Follower.Footer" = "لا يُمكِن عَرض المُتابِعين مِنَ الخوادم الأُخرى."; "Scene.Following.Footer" = "لا يُمكِن عَرض المُتابَعات مِنَ الخوادم الأُخرى."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict index 32782f1c..c2f64172 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict @@ -471,15 +471,15 @@ zero مُنذُ لَحظة one - مُنذُ سنة + مُنذُ %ldع two - مُنذُ سنتين + مُنذُ %ldع few - مُنذُ %ld سنين + مُنذُ %ldع many - مُنذُ %ld سنةً + مُنذُ %ldع other - مُنذُ %ld سنة + مُنذُ %ldع date.month.ago.abbr @@ -495,15 +495,15 @@ zero مُنذُ لَحظة one - مُنذُ شهر + مُنذُ %ldش two - مُنذُ شهرين + مُنذُ %ldش few - مُنذُ %ld أشهُر + مُنذُ %ldش many - مُنذُ %ld شهرًا + مُنذُ %ldش other - مُنذُ %ld شهر + مُنذُ %ldش date.day.ago.abbr @@ -519,15 +519,15 @@ zero مُنذُ لَحظة one - مُنذُ يوم + مُنذُ %ldي two - مُنذُ يومين + مُنذُ %ldي few - مُنذُ %ld أيام + مُنذُ %ldي many - مُنذُ %ld يومًا + مُنذُ %ldي other - مُنذُ %ld يوم + مُنذُ %ldي date.hour.ago.abbr @@ -543,15 +543,15 @@ zero مُنذُ لَحظة one - مُنذُ ساعة + مُنذُ %ldس two - مُنذُ ساعتين + مُنذُ %ldس few - مُنذُ %ld ساعات + مُنذُ %ldس many - مُنذُ %ld ساعةًَ + مُنذُ %ldس other - مُنذُ %ld ساعة + مُنذُ %ldس date.minute.ago.abbr @@ -567,15 +567,15 @@ zero مُنذُ لَحظة one - مُنذُ دقيقة + مُنذُ %ldد two - مُنذُ دقيقتان + مُنذُ %ldد few - مُنذُ %ld دقائق + مُنذُ %ldد many - مُنذُ %ld دقيقةً + مُنذُ %ldد other - مُنذُ %ld دقيقة + مُنذُ %ldد date.second.ago.abbr @@ -591,15 +591,15 @@ zero مُنذُ لَحظة one - مُنذُ ثانية + مُنذُ %ldث two - مُنذُ ثانيتين + مُنذُ %ldث few - مُنذُ %ld ثوان + مُنذُ %ldث many - مُنذُ %ld ثانية + مُنذُ %ldث other - مُنذُ %ld ثانية + مُنذُ %ldث diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings index 0cb63f34..4e10ce16 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings @@ -5,7 +5,7 @@ "Common.Alerts.Common.PleaseTryAgain" = "Si us plau intenta-ho de nou."; "Common.Alerts.Common.PleaseTryAgainLater" = "Si us plau, prova-ho més tard."; "Common.Alerts.DeletePost.Message" = "Estàs segur que vols suprimir aquesta publicació?"; -"Common.Alerts.DeletePost.Title" = "Estàs segur que vols suprimir aquesta publicació?"; +"Common.Alerts.DeletePost.Title" = "Esborrar Publicació"; "Common.Alerts.DiscardPostContent.Message" = "Confirma per a descartar el contingut de la publicació composta."; "Common.Alerts.DiscardPostContent.Title" = "Descarta l'esborrany"; "Common.Alerts.EditProfileFailure.Message" = "No es pot editar el perfil. Si us plau torna-ho a provar."; @@ -16,7 +16,7 @@ Comprova la teva connexió a Internet."; "Common.Alerts.PublishPostFailure.Title" = "Error de Publicació"; "Common.Alerts.SavePhotoFailure.Message" = "Activa el permís d'accés a la biblioteca de fotos per desar-la."; -"Common.Alerts.SavePhotoFailure.Title" = "Desa l'Error de la Foto"; +"Common.Alerts.SavePhotoFailure.Title" = "Error al Desar la Foto"; "Common.Alerts.ServerError.Title" = "Error del Servidor"; "Common.Alerts.SignOut.Confirm" = "Tancar Sessió"; "Common.Alerts.SignOut.Message" = "Estàs segur que vols tancar la sessió?"; @@ -36,7 +36,7 @@ Comprova la teva connexió a Internet."; "Common.Controls.Actions.Discard" = "Descarta"; "Common.Controls.Actions.Done" = "Fet"; "Common.Controls.Actions.Edit" = "Edita"; -"Common.Controls.Actions.FindPeople" = "Busca persones per seguir"; +"Common.Controls.Actions.FindPeople" = "Busca persones a seguir"; "Common.Controls.Actions.ManuallySearch" = "Cerca manualment a canvi"; "Common.Controls.Actions.Next" = "Següent"; "Common.Controls.Actions.Ok" = "D'acord"; @@ -81,18 +81,18 @@ Comprova la teva connexió a Internet."; "Common.Controls.Keyboard.Common.OpenSettings" = "Obre la configuració"; "Common.Controls.Keyboard.Common.ShowFavorites" = "Mostra els Favorits"; "Common.Controls.Keyboard.Common.SwitchToTab" = "Canviar a %@"; -"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Secció següent"; -"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Secció anterior"; +"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Secció Següent"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Secció Anterior"; "Common.Controls.Keyboard.Timeline.NextStatus" = "Publicació següent"; -"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Obre el perfil de l'autor"; -"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Obre el perfil del impulsor"; +"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Obre el Perfil de l'Autor"; +"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Obre el Perfil del Impulsor"; "Common.Controls.Keyboard.Timeline.OpenStatus" = "Obre la publicació"; "Common.Controls.Keyboard.Timeline.PreviewImage" = "Vista prèvia de l'Imatge"; "Common.Controls.Keyboard.Timeline.PreviousStatus" = "Publicació anterior"; -"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Respon a la publicació"; +"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Respon a la Publicació"; "Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Commuta l'Avís de Contingut"; -"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Commuta el Favorit de la publicació"; -"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Commuta l'impuls de la publicació"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Commuta el Favorit de la Publicació"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Commuta l'Impuls de la Publicació"; "Common.Controls.Status.Actions.Favorite" = "Favorit"; "Common.Controls.Status.Actions.Hide" = "Amaga"; "Common.Controls.Status.Actions.Menu" = "Menú"; @@ -105,10 +105,10 @@ Comprova la teva connexió a Internet."; "Common.Controls.Status.Actions.Unfavorite" = "Desfer Favorit"; "Common.Controls.Status.Actions.Unreblog" = "Desfer l'impuls"; "Common.Controls.Status.ContentWarning" = "Advertència de Contingut"; -"Common.Controls.Status.MediaContentWarning" = "Toca qualsevol lloc per mostrar"; +"Common.Controls.Status.MediaContentWarning" = "Toca qualsevol lloc per a mostrar"; "Common.Controls.Status.Poll.Closed" = "Finalitzada"; "Common.Controls.Status.Poll.Vote" = "Vota"; -"Common.Controls.Status.ShowPost" = "Mostra la publicació"; +"Common.Controls.Status.ShowPost" = "Mostra la Publicació"; "Common.Controls.Status.ShowUserProfile" = "Mostra el perfil de l'usuari"; "Common.Controls.Status.Tag.Email" = "Correu electrònic"; "Common.Controls.Status.Tag.Emoji" = "Emoji"; @@ -129,7 +129,7 @@ Comprova la teva connexió a Internet."; "Common.Controls.Tabs.Search" = "Cerca"; "Common.Controls.Timeline.Filtered" = "Filtrat"; "Common.Controls.Timeline.Header.BlockedWarning" = "No pots veure el perfil d'aquest usuari - fins que et desbloquegi."; +fins que et desbloquegi."; "Common.Controls.Timeline.Header.BlockingWarning" = "No pots veure el perfil d'aquest usuari fins que el desbloquegis. El teu perfil els sembla així."; @@ -141,8 +141,8 @@ El teu perfil els sembla així."; fins que el desbloquegis. El teu perfil els sembla així."; "Common.Controls.Timeline.Header.UserSuspendedWarning" = "El compte de %@ ha estat suspès."; -"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Carrega les publicacions que falten"; -"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Carregant les publicacions que falten..."; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Carrega les publicacions faltants"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Carregant les publicacions faltants..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Mostra més respostes"; "Common.Controls.Timeline.Timestamp.Now" = "Ara"; "Scene.AccountList.AddAccount" = "Afegir compte"; @@ -198,9 +198,12 @@ carregat a Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Mail" = "Correu electrònic"; "Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Obre el Client de Correu electrònic"; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Comprova la teva safata d'entrada."; -"Scene.ConfirmEmail.Subtitle" = "Acabem d'enviar un correu electrònic a %@, -toca l'enllaç per a confirmar el teu compte."; +"Scene.ConfirmEmail.Subtitle" = "Toca l'enllaç del correu electrònic que t'hem enviat per a confirmar el teu compte."; "Scene.ConfirmEmail.Title" = "Una última cosa."; +"Scene.Discovery.Tabs.ForYou" = "Per a tu"; +"Scene.Discovery.Tabs.Hashtags" = "Etiquetes"; +"Scene.Discovery.Tabs.News" = "Notícies"; +"Scene.Discovery.Tabs.Posts" = "Publicacions"; "Scene.Favorite.Title" = "Els teus Favorits"; "Scene.Follower.Footer" = "Els seguidors d'altres servidors no son mostrats."; "Scene.Following.Footer" = "Els seguits d'altres servidors no son mostrats."; @@ -263,7 +266,7 @@ toca l'enllaç per a confirmar el teu compte."; "Scene.Register.Error.Reason.Unreachable" = "%@ sembla que no existeix"; "Scene.Register.Error.Special.EmailInvalid" = "Aquesta no és una adreça de correu electrònic vàlida"; "Scene.Register.Error.Special.PasswordTooShort" = "La contrasenya és massa curta (ha de tenir 8 caràcters com a mínim)"; -"Scene.Register.Error.Special.UsernameInvalid" = "El nom d'usuari només ha de contenir caràcters alfanumèrics i guions baixos"; +"Scene.Register.Error.Special.UsernameInvalid" = "El nom d'usuari ha de contenir només caràcters alfanumèrics i guions baixos"; "Scene.Register.Error.Special.UsernameTooLong" = "El nom d'usuari és massa llarg (no pot ser més llarg de 30 caràcters)"; "Scene.Register.Input.Avatar.Delete" = "Suprimeix"; "Scene.Register.Input.DisplayName.Placeholder" = "nom visible"; @@ -272,7 +275,7 @@ toca l'enllaç per a confirmar el teu compte."; "Scene.Register.Input.Password.Accessibility.Checked" = "verificat"; "Scene.Register.Input.Password.Accessibility.Unchecked" = "no verificat"; "Scene.Register.Input.Password.CharacterLimit" = "8 caràcters"; -"Scene.Register.Input.Password.Hint" = "La teva contrasenya ha de tenir com a mínim buit caràcters"; +"Scene.Register.Input.Password.Hint" = "La teva contrasenya ha de tenir com a mínim vuit caràcters"; "Scene.Register.Input.Password.Placeholder" = "contrasenya"; "Scene.Register.Input.Password.Require" = "La teva contrasenya com a mínim necessita:"; "Scene.Register.Input.Username.DuplicatePrompt" = "Aquest nom d'usuari ja està en ús."; @@ -331,8 +334,7 @@ toca l'enllaç per a confirmar el teu compte."; "Scene.ServerPicker.Label.Users" = "USUARIS"; "Scene.ServerPicker.Subtitle" = "Tria una comunitat segons els teus interessos, regió o una de propòsit general."; "Scene.ServerPicker.SubtitleExtend" = "Tria una comunitat segons els teus interessos, regió o una de propòsit general. Cada comunitat és operada per una organització totalment independent o individualment."; -"Scene.ServerPicker.Title" = "Tria un servidor, -qualsevol servidor."; +"Scene.ServerPicker.Title" = "Mastodon està fet d'usuaris en diferents comunitats."; "Scene.ServerRules.Button.Confirm" = "Hi estic d'acord"; "Scene.ServerRules.PrivacyPolicy" = "política de privadesa"; "Scene.ServerRules.Prompt" = "Al continuar, estàs subjecte als termes de servei i a la política de privacitat de %@."; @@ -362,7 +364,7 @@ qualsevol servidor."; "Scene.Settings.Section.Notifications.Trigger.Anyone" = "algú"; "Scene.Settings.Section.Notifications.Trigger.Follow" = "a qualsevol que segueixi"; "Scene.Settings.Section.Notifications.Trigger.Follower" = "un seguidor"; -"Scene.Settings.Section.Notifications.Trigger.Noone" = "algú"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "ningú"; "Scene.Settings.Section.Notifications.Trigger.Title" = "Notifica'm quan"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Desactiva avatars animats"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Desactiva emojis animats"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings index 325b1e94..06f5eedf 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings @@ -98,10 +98,10 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Status.Actions.Menu" = "Menü"; "Common.Controls.Status.Actions.Reblog" = "Teilen"; "Common.Controls.Status.Actions.Reply" = "Antworten"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "GIF anzeigen"; +"Common.Controls.Status.Actions.ShowImage" = "Bild anzeigen"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Zeige Video-Player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Halte gedrückt um das Menü anzuzeigen"; "Common.Controls.Status.Actions.Unfavorite" = "Aus Favoriten entfernen"; "Common.Controls.Status.Actions.Unreblog" = "Nicht mehr teilen"; "Common.Controls.Status.ContentWarning" = "Inhaltswarnung"; @@ -116,7 +116,7 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Status.Tag.Link" = "Link"; "Common.Controls.Status.Tag.Mention" = "Erwähnung"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "Zum Anzeigen tippen"; "Common.Controls.Status.UserReblogged" = "%@ teilte"; "Common.Controls.Status.UserRepliedTo" = "Antwortet auf %@"; "Common.Controls.Status.Visibility.Direct" = "Nur erwähnte Benutzer können diesen Beitrag sehen."; @@ -201,6 +201,10 @@ kann nicht auf Mastodon hochgeladen werden."; "Scene.ConfirmEmail.Subtitle" = "Wir haben gerade eine E-Mail an %@ gesendet, tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.ConfirmEmail.Title" = "Noch eine letzte Sache."; +"Scene.Discovery.Tabs.ForYou" = "Für dich"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "Nachrichten"; +"Scene.Discovery.Tabs.Posts" = "Beiträge"; "Scene.Favorite.Title" = "Deine Favoriten"; "Scene.Follower.Footer" = "Follower von anderen Servern werden nicht angezeigt."; "Scene.Following.Footer" = "Wem das Konto folgt wird von anderen Servern werden nicht angezeigt."; @@ -222,10 +226,10 @@ tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.Preview.Keyboard.ClosePreview" = "Vorschau schließen"; "Scene.Preview.Keyboard.ShowNext" = "Nächstes anzeigen"; "Scene.Preview.Keyboard.ShowPrevious" = "Vorheriges anzeigen"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Doppeltippen, um die Liste zu öffnen"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Profilbild bearbeiten"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Profilbild anzeigen"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Bannerbild anzeigen"; "Scene.Profile.Dashboard.Followers" = "Folger"; "Scene.Profile.Dashboard.Following" = "Gefolgte"; "Scene.Profile.Dashboard.Posts" = "Beiträge"; @@ -366,7 +370,7 @@ beliebigen Server."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Benachrichtige mich, wenn"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Animierte Profilbilder deaktivieren"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Animierte Emojis deaktivieren"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Links in Mastodon öffnen"; "Scene.Settings.Section.Preference.Title" = "Präferenzen"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Vollständig dunkler Dunkelmodus"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Standardbrowser zum Öffnen von Links verwenden"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict index cd721862..20e8b615 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 Antwort other - %ld replies + %ld Antworten plural.count.vote diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings index 285c185b..4edf4702 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -200,6 +200,10 @@ uploaded to Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Check your inbox."; "Scene.ConfirmEmail.Subtitle" = "Tap the link we emailed to you to verify your account."; "Scene.ConfirmEmail.Title" = "One last thing."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Your Favorites"; "Scene.Follower.Footer" = "Followers from other servers are not displayed."; "Scene.Following.Footer" = "Follows from other servers are not displayed."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings index f3670fb6..0782206f 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings @@ -5,7 +5,7 @@ "Common.Alerts.Common.PleaseTryAgain" = "Por favor, intentá de nuevo."; "Common.Alerts.Common.PleaseTryAgainLater" = "Por favor, intentá de nuevo más tarde."; "Common.Alerts.DeletePost.Message" = "¿Estás seguro que querés eliminar este mensaje?"; -"Common.Alerts.DeletePost.Title" = "¿Estás seguro que querés eliminar este mensaje?"; +"Common.Alerts.DeletePost.Title" = "Eliminar mensaje"; "Common.Alerts.DiscardPostContent.Message" = "Confirmá para descartar el contenido del mensaje redactado."; "Common.Alerts.DiscardPostContent.Title" = "Descartar borrador"; "Common.Alerts.EditProfileFailure.Message" = "No se pudo editar el perfil. Por favor, intentá de nuevo."; @@ -201,6 +201,10 @@ y no se puede subir a Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Acabamos de enviar un correo electrónico a %@, pulsá en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; +"Scene.Discovery.Tabs.ForYou" = "Para vos"; +"Scene.Discovery.Tabs.Hashtags" = "Etiquetas"; +"Scene.Discovery.Tabs.News" = "Novedades"; +"Scene.Discovery.Tabs.Posts" = "Mensajes"; "Scene.Favorite.Title" = "Tus favoritos"; "Scene.Follower.Footer" = "No se muestran los seguidores de otros servidores."; "Scene.Following.Footer" = "No se muestran las cuentas de otros servidores que seguís."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings index 4cbebb3e..544a0b86 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings @@ -201,6 +201,10 @@ subirse a Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Te acabamos de enviar un correo a %@, pulsa en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Tus Favoritos"; "Scene.Follower.Footer" = "No se muestran los seguidores de otros servidores."; "Scene.Following.Footer" = "No se muestran los seguidos de otros servidores."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings index 341f4862..42b3bfb6 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings @@ -98,10 +98,10 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Status.Actions.Menu" = "Menua"; "Common.Controls.Status.Actions.Reblog" = "Bultzada"; "Common.Controls.Status.Actions.Reply" = "Erantzun"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "Erakutsi GIFa"; +"Common.Controls.Status.Actions.ShowImage" = "Erakutsi irudia"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Erakutsi bideo-erreproduzigailua"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Sakatu eta eutsi menua erakusteko"; "Common.Controls.Status.Actions.Unfavorite" = "Kendu gogokoa"; "Common.Controls.Status.Actions.Unreblog" = "Desegin bultzada"; "Common.Controls.Status.ContentWarning" = "Edukiaren abisua"; @@ -116,7 +116,7 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Status.Tag.Link" = "Esteka"; "Common.Controls.Status.Tag.Mention" = "Aipatu"; "Common.Controls.Status.Tag.Url" = "URLa"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "Sakatu erakusteko"; "Common.Controls.Status.UserReblogged" = "%@ erabiltzaileak bultzada eman dio"; "Common.Controls.Status.UserRepliedTo" = "%@(r)i erantzuten"; "Common.Controls.Status.Visibility.Direct" = "Aipatutako erabiltzaileek soilik ikus dezakete bidalketa hau."; @@ -201,6 +201,10 @@ Mastodonera igo."; "Scene.ConfirmEmail.Subtitle" = "Eposta bat bidali dizugu %@ helbidera, sakatu kontua berresteko esteka."; "Scene.ConfirmEmail.Title" = "Eta azkenik..."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Zure gogokoak"; "Scene.Follower.Footer" = "Beste zerbitzarietako jarraitzaileak ez dira bistaratzen."; "Scene.Following.Footer" = "Beste zerbitzarietan jarraitutakoak ez dira bistaratzen."; @@ -211,21 +215,21 @@ sakatu kontua berresteko esteka."; "Scene.HomeTimeline.Title" = "Hasiera"; "Scene.Notification.Keyobard.ShowEverything" = "Erakutsi guztia"; "Scene.Notification.Keyobard.ShowMentions" = "Erakutsi aipamenak"; -"Scene.Notification.NotificationDescription.FavoritedYourPost" = "erabiltzaileak zure bidalketa gogoko du"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "(e)k zure bidalketa gogoko du"; "Scene.Notification.NotificationDescription.FollowedYou" = "zu jarraitzen hasi da"; "Scene.Notification.NotificationDescription.MentionedYou" = "erabiltzaileak aipatu zaitu"; "Scene.Notification.NotificationDescription.PollHasEnded" = "inkesta amaitu da"; -"Scene.Notification.NotificationDescription.RebloggedYourPost" = "erabiltzaileak bultzada eman dio zure bidalketari"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "(e)k bultzada eman dio zure bidalketari"; "Scene.Notification.NotificationDescription.RequestToFollowYou" = "erabiltzaileak zu jarraitzea eskatu du"; "Scene.Notification.Title.Everything" = "Dena"; "Scene.Notification.Title.Mentions" = "Aipamenak"; "Scene.Preview.Keyboard.ClosePreview" = "Itxi aurrebista"; "Scene.Preview.Keyboard.ShowNext" = "Erakutsi hurrengoa"; "Scene.Preview.Keyboard.ShowPrevious" = "Erakutsi aurrekoa"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Sakatu birritan zerrenda irekitzeko"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Editatu abatarra"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Erakutsi abatarra"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Erakutsi banner irudia"; "Scene.Profile.Dashboard.Followers" = "jarraitzaile"; "Scene.Profile.Dashboard.Following" = "jarraitzen"; "Scene.Profile.Dashboard.Posts" = "bidalketa"; @@ -366,7 +370,7 @@ edozein zerbitzari."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Noiz jakinarazi:"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Desgaitu abatar animatuak"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Desgaitu emoji animatuak"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Ireki estekak Mastodonen"; "Scene.Settings.Section.Preference.Title" = "Hobespenak"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Benetako modu beltz iluna"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Erabili nabigatzaile lehenetsia estekak irekitzeko"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict index 2069e27a..871fb10b 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + Erantzun bat other - %ld replies + %ld erantzun plural.count.vote diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings index 69aa3172..0ed3a271 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings @@ -98,9 +98,9 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Status.Actions.Menu" = "Menu"; "Common.Controls.Status.Actions.Reblog" = "Rebloguer"; "Common.Controls.Status.Actions.Reply" = "Répondre"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.ShowGif" = "Afficher le GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Afficher l’image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Afficher le lecteur vidéo"; "Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "Retirer des favoris"; "Common.Controls.Status.Actions.Unreblog" = "Annuler le reblog"; @@ -116,7 +116,7 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Status.Tag.Link" = "Lien"; "Common.Controls.Status.Tag.Mention" = "Mention"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "Appuyer pour afficher"; "Common.Controls.Status.UserReblogged" = "%@ a reblogué"; "Common.Controls.Status.UserRepliedTo" = "À répondu à %@"; "Common.Controls.Status.Visibility.Direct" = "Seul·e l’utilisateur·rice mentionnée peut voir ce message."; @@ -201,6 +201,10 @@ téléversé sur Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Nous venons d’envoyer un courriel à %@, tapotez le lien pour confirmer votre compte."; "Scene.ConfirmEmail.Title" = "Une dernière chose."; +"Scene.Discovery.Tabs.ForYou" = "Pour vous"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "Actualité"; +"Scene.Discovery.Tabs.Posts" = "Messages"; "Scene.Favorite.Title" = "Vos favoris"; "Scene.Follower.Footer" = "Les abonné·e·s issus des autres serveurs ne sont pas affiché·e·s."; "Scene.Following.Footer" = "Les abonnés issus des autres serveurs ne sont pas affichés."; @@ -222,10 +226,10 @@ tapotez le lien pour confirmer votre compte."; "Scene.Preview.Keyboard.ClosePreview" = "Fermer l'aperçu"; "Scene.Preview.Keyboard.ShowNext" = "Afficher le suivant"; "Scene.Preview.Keyboard.ShowPrevious" = "Afficher le précédent"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Appuyer deux fois pour ouvrir la liste"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Modifier l’avatar"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Afficher l’avatar"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Afficher l’image de la bannière"; "Scene.Profile.Dashboard.Followers" = "abonnés"; "Scene.Profile.Dashboard.Following" = "abonnements"; "Scene.Profile.Dashboard.Posts" = "publications"; @@ -366,7 +370,7 @@ n'importe quel serveur."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Me notifier lorsque"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Désactiver les avatars animés"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Désactiver les émojis animées"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Ouvrir les liens dans Mastodon"; "Scene.Settings.Section.Preference.Title" = "Préférences"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Vrai mode sombre"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Utiliser le navigateur par défaut pour ouvrir les liens"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict index 93ee696f..5c2b1497 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 réponse other - %ld replies + %ld réponses plural.count.vote diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings index 9e4ab602..91bc1373 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings @@ -201,6 +201,10 @@ a luchdadh suas gu Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Tha sinn air post-d a chur gu %@, thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.ConfirmEmail.Title" = "Aon rud eile."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Na h-annsachdan agad"; "Scene.Follower.Footer" = "Cha dèid luchd-leantainn o fhrithealaichean eile a shealltainn."; "Scene.Following.Footer" = "Cha dèid cò air a leanas tu air frithealaichean eile a shealltainn."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings index a8164db9..339e23f1 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings @@ -195,6 +195,10 @@ "Scene.ConfirmEmail.OpenEmailApp.Title" = "メールを確認"; "Scene.ConfirmEmail.Subtitle" = "先程 %@ にメールを送信しました。リンクをタップしてアカウントを確認してください。"; "Scene.ConfirmEmail.Title" = "さいごにもうひとつ。"; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "お気に入り"; "Scene.Follower.Footer" = "他のサーバーからのフォロワーは表示されません。"; "Scene.Following.Footer" = "他のサーバーにいるフォローは表示されません。"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings index 55b8a3a6..792cf368 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings @@ -200,6 +200,10 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Sefqed Tanaka-inek."; "Scene.ConfirmEmail.Subtitle" = "Sit ɣef useɣwen i ak-n-uznen i wakken ad tesneqdeḍ amiḍan-ik."; "Scene.ConfirmEmail.Title" = "Taɣawsa taneggarut."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Ismenyifen-ik·im"; "Scene.Follower.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; "Scene.Following.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings index 608163f4..dcc8dae6 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings @@ -201,6 +201,10 @@ Profîla te ji wan ra wiha xuya dike."; "Scene.ConfirmEmail.Subtitle" = "Me tenê e-nameyek ji %@ re şand, girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.ConfirmEmail.Title" = "Tiştekî dawî."; +"Scene.Discovery.Tabs.ForYou" = "Ji bo te"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtag"; +"Scene.Discovery.Tabs.News" = "Nûçe"; +"Scene.Discovery.Tabs.Posts" = "Şandî"; "Scene.Favorite.Title" = "Bijarteyên te"; "Scene.Follower.Footer" = "Şopîner ji rajekerên din nayê dîtin."; "Scene.Following.Footer" = "Şopandin ji rajekerên din nayê dîtin."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings index 6a19a4bf..31148373 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings @@ -195,6 +195,10 @@ Uw profiel ziet er zo uit voor hen."; "Scene.ConfirmEmail.Subtitle" = "We hebben een e-mail gestuurd naar %@, klik op de link om uw account te bevestigen."; "Scene.ConfirmEmail.Title" = "Nog één ding."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Uw favorieten"; "Scene.Follower.Footer" = "Followers from other servers are not displayed."; "Scene.Following.Footer" = "Follows from other servers are not displayed."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings index 6913d753..d7ed34c3 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings @@ -4,7 +4,7 @@ "Common.Alerts.CleanCache.Title" = "Очистка кэша"; "Common.Alerts.Common.PleaseTryAgain" = "Пожалуйста, попробуйте ещё раз."; "Common.Alerts.Common.PleaseTryAgainLater" = "Пожалуйста, попробуйте позже."; -"Common.Alerts.DeletePost.Message" = "Are you sure you want to delete this post?"; +"Common.Alerts.DeletePost.Message" = "Вы уверены, что хотите удалить этот пост?"; "Common.Alerts.DeletePost.Title" = "Вы уверены, что хотите удалить этот пост?"; "Common.Alerts.DiscardPostContent.Message" = "Вы действительно хотите удалить набранное содержимое поста?"; "Common.Alerts.DiscardPostContent.Title" = "Удалить черновик"; @@ -69,7 +69,7 @@ "Common.Controls.Friendship.Follow" = "Подписаться"; "Common.Controls.Friendship.Following" = "В подписках"; "Common.Controls.Friendship.Mute" = "Игнорировать"; -"Common.Controls.Friendship.MuteUser" = "Добавить %@ в игнорируемые"; +"Common.Controls.Friendship.MuteUser" = "Игнорировать %@"; "Common.Controls.Friendship.Muted" = "В игнорируемых"; "Common.Controls.Friendship.Pending" = "Отправлен"; "Common.Controls.Friendship.Request" = "Отправить запрос"; @@ -94,14 +94,14 @@ "Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Добавить или убрать из избранного"; "Common.Controls.Keyboard.Timeline.ToggleReblog" = "Продвинуть или убрать продвижение"; "Common.Controls.Status.Actions.Favorite" = "Добавить в избранное"; -"Common.Controls.Status.Actions.Hide" = "Hide"; +"Common.Controls.Status.Actions.Hide" = "Скрыть"; "Common.Controls.Status.Actions.Menu" = "Меню"; "Common.Controls.Status.Actions.Reblog" = "Продвинуть"; "Common.Controls.Status.Actions.Reply" = "Ответить"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "Показать GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Показать изображение"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Показать видеопроигрыватель"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Нажмите и удерживайте, чтобы показать меню"; "Common.Controls.Status.Actions.Unfavorite" = "Убрать из избранного"; "Common.Controls.Status.Actions.Unreblog" = "Убрать продвижение"; "Common.Controls.Status.ContentWarning" = "Предупреждение о содержании"; @@ -116,7 +116,7 @@ "Common.Controls.Status.Tag.Link" = "Ссылка"; "Common.Controls.Status.Tag.Mention" = "Упоминание"; "Common.Controls.Status.Tag.Url" = "Ссылка"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "Нажмите, чтобы показать"; "Common.Controls.Status.UserReblogged" = "%@ продвинул(а)"; "Common.Controls.Status.UserRepliedTo" = "Ответил(а) %@"; "Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; @@ -198,7 +198,7 @@ "Scene.Compose.Visibility.Public" = "Публичный"; "Scene.Compose.Visibility.Unlisted" = "Скрытый"; "Scene.ConfirmEmail.Button.OpenEmailApp" = "Открыть приложение почты"; -"Scene.ConfirmEmail.Button.Resend" = "Resend"; +"Scene.ConfirmEmail.Button.Resend" = "Отправить заново"; "Scene.ConfirmEmail.DontReceiveEmail.Description" = "Проверьте, правильно ли указан ваш e-mail адрес, а также папку «спам», если ещё не сделали этого."; "Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Отправить ещё раз"; "Scene.ConfirmEmail.DontReceiveEmail.Title" = "Проверьте свой e-mail адрес"; @@ -211,6 +211,10 @@ Нажмите на ссылку в нём, чтобы подтвердить свою учётную запись."; "Scene.ConfirmEmail.Title" = "И ещё кое-что."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Ваше избранное"; "Scene.Follower.Footer" = "Followers from other servers are not displayed."; "Scene.Following.Footer" = "Follows from other servers are not displayed."; @@ -253,7 +257,7 @@ "Scene.Profile.SegmentedControl.About" = "About"; "Scene.Profile.SegmentedControl.Media" = "Медиа"; "Scene.Profile.SegmentedControl.Posts" = "Посты"; -"Scene.Profile.SegmentedControl.PostsAndReplies" = "Posts and Replies"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "Посты и ответы"; "Scene.Profile.SegmentedControl.Replies" = "Ответы"; "Scene.Register.Error.Item.Agreement" = "Соглашение"; "Scene.Register.Error.Item.Email" = "E-mail"; @@ -298,7 +302,7 @@ "Scene.Report.Step2" = "Шаг 2 из 2"; "Scene.Report.TextPlaceholder" = "Дополнительные комментарии"; "Scene.Report.Title" = "Пожаловаться на %@"; -"Scene.Report.TitleReport" = "Report"; +"Scene.Report.TitleReport" = "Жалоба"; "Scene.Search.Recommend.Accounts.Description" = "Возможно, вы захотите подписаться на эти профили"; "Scene.Search.Recommend.Accounts.Follow" = "Подписаться"; "Scene.Search.Recommend.Accounts.Title" = "Вам может понравится"; @@ -376,7 +380,7 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "Уведомлять меня, когда"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Отключить анимацию аватарок"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Отключить анимацию эмодзи"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Открывать ссылки в Мастодоне"; "Scene.Settings.Section.Preference.Title" = "Предпочтения"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Полноценно чёрный режим"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Использовать браузер по умолчанию для открытия ссылок"; @@ -388,10 +392,10 @@ "Scene.SuggestionAccount.Title" = "Подпишитесь на людей"; "Scene.Thread.BackTitle" = "Пост"; "Scene.Thread.Title" = "Пост %@"; -"Scene.Welcome.GetStarted" = "Get Started"; +"Scene.Welcome.GetStarted" = "Присоединиться"; "Scene.Welcome.LogIn" = "Вход"; "Scene.Welcome.Slogan" = "Социальная сеть под вашим контролем."; "Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; "Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.NewInMastodon" = "Новое в Мастодоне"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings index 07d5aa5e..434303e3 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings @@ -200,6 +200,10 @@ uploaded to Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Tarkasta postilaatikkosi."; "Scene.ConfirmEmail.Subtitle" = "Lähetimme juuri sähköpostin osoitteeseen %@, napauta siinä olevaa linkkiä vahvistaaksesi tilisi."; "Scene.ConfirmEmail.Title" = "Viimeinen asia."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Omat suosikit"; "Scene.Follower.Footer" = "Seuraajia muilta palvelimilta ei näytetä."; "Scene.Following.Footer" = "Seurauksia muilta palvelimilta ei näytetä."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings index de50842f..5dfb5134 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings @@ -98,10 +98,10 @@ "Common.Controls.Status.Actions.Menu" = "เมนู"; "Common.Controls.Status.Actions.Reblog" = "ดัน"; "Common.Controls.Status.Actions.Reply" = "ตอบกลับ"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "แสดง GIF"; +"Common.Controls.Status.Actions.ShowImage" = "แสดงภาพ"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "แสดงตัวเล่นวิดีโอ"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "แตะค้างไว้เพื่อแสดงเมนู"; "Common.Controls.Status.Actions.Unfavorite" = "เลิกชื่นชอบ"; "Common.Controls.Status.Actions.Unreblog" = "เลิกทำการดัน"; "Common.Controls.Status.ContentWarning" = "คำเตือนเนื้อหา"; @@ -116,7 +116,7 @@ "Common.Controls.Status.Tag.Link" = "ลิงก์"; "Common.Controls.Status.Tag.Mention" = "กล่าวถึง"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "แตะเพื่อเปิดเผย"; "Common.Controls.Status.UserReblogged" = "%@ ได้ดัน"; "Common.Controls.Status.UserRepliedTo" = "ตอบกลับ %@"; "Common.Controls.Status.Visibility.Direct" = "เฉพาะผู้ใช้ที่กล่าวถึงเท่านั้นที่สามารถเห็นโพสต์นี้"; @@ -200,6 +200,10 @@ "Scene.ConfirmEmail.OpenEmailApp.Title" = "ตรวจสอบกล่องขาเข้าของคุณ"; "Scene.ConfirmEmail.Subtitle" = "แตะลิงก์ที่เราส่งอีเมลถึงคุณเพื่อยืนยันบัญชีของคุณ"; "Scene.ConfirmEmail.Title" = "หนึ่งสิ่งสุดท้าย"; +"Scene.Discovery.Tabs.ForYou" = "สำหรับคุณ"; +"Scene.Discovery.Tabs.Hashtags" = "แฮชแท็ก"; +"Scene.Discovery.Tabs.News" = "ข่าว"; +"Scene.Discovery.Tabs.Posts" = "โพสต์"; "Scene.Favorite.Title" = "รายการโปรดของคุณ"; "Scene.Follower.Footer" = "ไม่ได้แสดงผู้ติดตามจากเซิร์ฟเวอร์อื่น ๆ"; "Scene.Following.Footer" = "ไม่ได้แสดงการติดตามจากเซิร์ฟเวอร์อื่น ๆ"; @@ -221,10 +225,10 @@ "Scene.Preview.Keyboard.ClosePreview" = "ปิดตัวอย่าง"; "Scene.Preview.Keyboard.ShowNext" = "แสดงถัดไป"; "Scene.Preview.Keyboard.ShowPrevious" = "แสดงก่อนหน้า"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "แตะสองครั้งเพื่อเปิดรายการ"; +"Scene.Profile.Accessibility.EditAvatarImage" = "แก้ไขภาพประจำตัว"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "แสดงภาพประจำตัว"; +"Scene.Profile.Accessibility.ShowBannerImage" = "แสดงภาพแบนเนอร์"; "Scene.Profile.Dashboard.Followers" = "ผู้ติดตาม"; "Scene.Profile.Dashboard.Following" = "กำลังติดตาม"; "Scene.Profile.Dashboard.Posts" = "โพสต์"; @@ -364,7 +368,7 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "แจ้งเตือนฉันเมื่อ"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "ปิดใช้งานภาพประจำตัวแบบเคลื่อนไหว"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "ปิดใช้งานอีโมจิแบบเคลื่อนไหว"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "เปิดลิงก์ใน Mastodon"; "Scene.Settings.Section.Preference.Title" = "การกำหนดลักษณะ"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "โหมดมืดดำสนิท"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "ใช้เบราว์เซอร์เริ่มต้นเพื่อเปิดลิงก์"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict index 3895c399..8ae8feb7 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict @@ -111,7 +111,7 @@ NSStringFormatValueTypeKey ld other - %ld replies + %ld การตอบกลับ plural.count.vote diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings index 95eef33b..407c4f9c 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings @@ -8,8 +8,8 @@ "Common.Alerts.DeletePost.Title" = "Xóa tút"; "Common.Alerts.DiscardPostContent.Message" = "Xác nhận bỏ qua nội dung tút đã viết."; "Common.Alerts.DiscardPostContent.Title" = "Hủy bản nháp"; -"Common.Alerts.EditProfileFailure.Message" = "Không thể chỉnh sửa trang cá nhân. Vui lòng thử lại."; -"Common.Alerts.EditProfileFailure.Title" = "Lỗi chỉnh sửa trang cá nhân"; +"Common.Alerts.EditProfileFailure.Message" = "Không thể chỉnh sửa hồ sơ. Vui lòng thử lại."; +"Common.Alerts.EditProfileFailure.Title" = "Lỗi chỉnh sửa hồ sơ"; "Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Không thể đính kèm nhiều video."; "Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Không thể đính kèm video cùng với hình ảnh."; "Common.Alerts.PublishPostFailure.Message" = "Không thể đăng tút. @@ -109,7 +109,7 @@ Vui lòng kiểm tra kết nối mạng."; "Common.Controls.Status.Poll.Closed" = "Kết thúc"; "Common.Controls.Status.Poll.Vote" = "Bình chọn"; "Common.Controls.Status.ShowPost" = "Xem tút"; -"Common.Controls.Status.ShowUserProfile" = "Xem trang cá nhân"; +"Common.Controls.Status.ShowUserProfile" = "Xem trang hồ sơ"; "Common.Controls.Status.Tag.Email" = "Email"; "Common.Controls.Status.Tag.Emoji" = "Emoji"; "Common.Controls.Status.Tag.Hashtag" = "Hashtag"; @@ -125,7 +125,7 @@ Vui lòng kiểm tra kết nối mạng."; "Common.Controls.Status.Visibility.Unlisted" = "Ai cũng thấy tút này nhưng không hiện trên bảng tin máy chủ."; "Common.Controls.Tabs.Home" = "Bảng tin"; "Common.Controls.Tabs.Notification" = "Thông báo"; -"Common.Controls.Tabs.Profile" = "Trang cá nhân"; +"Common.Controls.Tabs.Profile" = "Trang hồ sơ"; "Common.Controls.Tabs.Search" = "Tìm kiếm"; "Common.Controls.Timeline.Filtered" = "Bộ lọc"; "Common.Controls.Timeline.Header.BlockedWarning" = "Bạn không thể xem trang người này @@ -200,6 +200,10 @@ tải lên Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Kiểm tra hộp thư của bạn."; "Scene.ConfirmEmail.Subtitle" = "Nhấn vào liên kết chúng tôi gửi qua email để xác thực tài khoản."; "Scene.ConfirmEmail.Title" = "Còn điều này nữa."; +"Scene.Discovery.Tabs.ForYou" = "Dành cho bạn"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtag"; +"Scene.Discovery.Tabs.News" = "Tin tức"; +"Scene.Discovery.Tabs.Posts" = "Tút"; "Scene.Favorite.Title" = "Lượt thích"; "Scene.Follower.Footer" = "Không hiển thị người theo dõi từ máy chủ khác."; "Scene.Following.Footer" = "Không hiển thị người bạn theo dõi từ máy chủ khác."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings index f4a90541..f9ec487c 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings @@ -98,10 +98,10 @@ "Common.Controls.Status.Actions.Menu" = "菜单"; "Common.Controls.Status.Actions.Reblog" = "转发"; "Common.Controls.Status.Actions.Reply" = "回复"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "显示 GIF"; +"Common.Controls.Status.Actions.ShowImage" = "显示图片"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "显示视频播放器"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "长按以显示菜单"; "Common.Controls.Status.Actions.Unfavorite" = "取消喜欢"; "Common.Controls.Status.Actions.Unreblog" = "取消转发"; "Common.Controls.Status.ContentWarning" = "内容警告"; @@ -116,7 +116,7 @@ "Common.Controls.Status.Tag.Link" = "链接"; "Common.Controls.Status.Tag.Mention" = "提及"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "点击以显示"; "Common.Controls.Status.UserReblogged" = "%@ 转发"; "Common.Controls.Status.UserRepliedTo" = "回复给 %@"; "Common.Controls.Status.Visibility.Direct" = "只有提到的用户才能看到此帖子。"; @@ -201,6 +201,10 @@ "Scene.ConfirmEmail.Subtitle" = "我们刚刚向 %@ 发送了一封电子邮件, 点击链接确认你的帐户。"; "Scene.ConfirmEmail.Title" = "最后一件事。"; +"Scene.Discovery.Tabs.ForYou" = "为你推荐"; +"Scene.Discovery.Tabs.Hashtags" = "话题"; +"Scene.Discovery.Tabs.News" = "新闻"; +"Scene.Discovery.Tabs.Posts" = "帖子"; "Scene.Favorite.Title" = "你的喜欢"; "Scene.Follower.Footer" = "不会显示来自其它服务器的关注者"; "Scene.Following.Footer" = "不会显示来自其它服务器的关注"; @@ -222,10 +226,10 @@ "Scene.Preview.Keyboard.ClosePreview" = "关闭预览"; "Scene.Preview.Keyboard.ShowNext" = "显示下一个"; "Scene.Preview.Keyboard.ShowPrevious" = "显示前一个"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "双击打开列表"; +"Scene.Profile.Accessibility.EditAvatarImage" = "编辑头像"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "显示头像"; +"Scene.Profile.Accessibility.ShowBannerImage" = "显示顶部横幅图片"; "Scene.Profile.Dashboard.Followers" = "关注者"; "Scene.Profile.Dashboard.Following" = "正在关注"; "Scene.Profile.Dashboard.Posts" = "帖子"; @@ -366,7 +370,7 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "提示通知来自"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "禁用动画头像"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "禁用动画表情"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "在 Mastodon 中打开链接"; "Scene.Settings.Section.Preference.Title" = "偏好"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "纯黑模式"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "使用默认浏览器打开链接"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict index 41890383..6c2661ee 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict @@ -111,7 +111,7 @@ NSStringFormatValueTypeKey ld other - %ld replies + %ld 条回复 plural.count.vote From c9a8834ff7e628d862211d4e6ba01abae6bfa786 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 17:58:44 +0800 Subject: [PATCH 183/188] chore: update version to 1.3.1 (111) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 14 ++++---- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 32 insertions(+), 32 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 66a4b22f..f6306ed3 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 83cbb62a..9343658e 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4725,7 +4725,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4754,7 +4754,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4862,11 +4862,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 110; + DYLIB_CURRENT_VERSION = 111; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4893,11 +4893,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 110; + DYLIB_CURRENT_VERSION = 111; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4922,7 +4922,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4947,7 +4947,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4972,7 +4972,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4997,7 +4997,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5083,7 +5083,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5150,11 +5150,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 110; + DYLIB_CURRENT_VERSION = 111; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5179,7 +5179,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5203,7 +5203,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5228,7 +5228,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5253,7 +5253,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5277,7 +5277,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 0d22a226..b7da0420 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -9,7 +9,7 @@ isShown orderHint - 5 + 4 CoreDataStack.xcscheme_^#shared#^_ @@ -19,7 +19,7 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 20 + 19 Mastodon - Release.xcscheme_^#shared#^_ @@ -29,12 +29,12 @@ Mastodon - Snapshot.xcscheme_^#shared#^_ orderHint - 3 + 2 Mastodon - ar.xcscheme orderHint - 4 + 3 Mastodon - ar.xcscheme_^#shared#^_ @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 26 + 30 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 23 + 31 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 24 + 29 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 88b45ec3..efd0d4f7 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 110 + 111 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 79748763..4842779e 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 66a4b22f..f6306ed3 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 66a4b22f..f6306ed3 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 7301c57d..82097f0e 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 85681881..8c23d89f 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 NSExtension NSExtensionAttributes From a9a83315b212a66101d94c76d5036dfeca390766 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 18:11:31 +0800 Subject: [PATCH 184/188] fix: searchTextField cover by keyboard issue. resolve #375 --- .../MastodonPickServerViewController.swift | 31 ++++++------------- .../MastodonPickServerViewModel.swift | 3 +- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift index 2d43faa5..b86c952a 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift @@ -12,6 +12,7 @@ import GameController import AuthenticationServices import MastodonAsset import MastodonLocalization +import MastodonUI final class MastodonPickServerViewController: UIViewController, NeedsDependency { @@ -144,6 +145,13 @@ extension MastodonPickServerViewController { pickServerServerSectionTableHeaderViewDelegate: self, pickServerCellDelegate: self ) + + KeyboardResponderService + .configure( + scrollView: tableView, + layoutNeedsUpdate: viewModel.viewDidAppear.eraseToAnyPublisher() + ) + .store(in: &disposeBag) viewModel .selectedServer @@ -238,6 +246,7 @@ extension MastodonPickServerViewController { super.viewDidAppear(animated) tableView.flashScrollIndicators() + viewModel.viewDidAppear.send() } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { @@ -416,28 +425,6 @@ extension MastodonPickServerViewController: UITableViewDelegate { viewModel.selectedServer.send(nil) } - func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { - guard let diffableDataSource = viewModel.diffableDataSource else { return } - guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } - - switch item { -// case .categoryPicker: -// guard let cell = cell as? PickServerCategoriesCell else { return } -// guard let diffableDataSource = cell.diffableDataSource else { return } -// let snapshot = diffableDataSource.snapshot() -// -// let item = viewModel.selectCategoryItem.value -// guard let section = snapshot.indexOfSection(.main), -// let row = snapshot.indexOfItem(item) else { return } -// cell.collectionView.selectItem(at: IndexPath(item: row, section: section), animated: false, scrollPosition: .centeredHorizontally) -// case .search: -// guard let cell = cell as? PickServerSearchCell else { return } -// cell.searchTextField.text = viewModel.searchText.value - default: - break - } - } - func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { guard let diffableDataSource = viewModel.diffableDataSource else { return nil } let snapshot = diffableDataSource.snapshot() diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift index af38b110..59008c53 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift @@ -45,7 +45,8 @@ class MastodonPickServerViewModel: NSObject { let indexedServers = CurrentValueSubject<[Mastodon.Entity.Server], Never>([]) let unindexedServers = CurrentValueSubject<[Mastodon.Entity.Server]?, Never>([]) // set nil when loading let viewWillAppear = PassthroughSubject() - + let viewDidAppear = CurrentValueSubject(Void()) + // output var diffableDataSource: UITableViewDiffableDataSource? private(set) lazy var loadIndexedServerStateMachine: GKStateMachine = { From 063119337d37623abf311cc302b12121f291a976 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 18:23:11 +0800 Subject: [PATCH 185/188] chore: update version to 1.3.1 (112) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index f6306ed3..a16d6ce2 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 9343658e..d7e76cd3 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4725,7 +4725,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4754,7 +4754,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4862,11 +4862,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 111; + DYLIB_CURRENT_VERSION = 112; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4893,11 +4893,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 111; + DYLIB_CURRENT_VERSION = 112; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4922,7 +4922,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4947,7 +4947,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4972,7 +4972,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4997,7 +4997,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5083,7 +5083,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5150,11 +5150,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 111; + DYLIB_CURRENT_VERSION = 112; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5179,7 +5179,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5203,7 +5203,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5228,7 +5228,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5253,7 +5253,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5277,7 +5277,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index b7da0420..ae6e6040 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 30 + 33 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 31 + 32 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 29 + 34 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index efd0d4f7..aa2be51b 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 111 + 112 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 4842779e..974ce601 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index f6306ed3..a16d6ce2 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index f6306ed3..a16d6ce2 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 82097f0e..20fbcea3 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 8c23d89f..1325a348 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 NSExtension NSExtensionAttributes From 1d966090032865362f1ec01442395889e26238ba Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 19 Apr 2022 20:57:21 +0800 Subject: [PATCH 186/188] fix: ProfileCardView layout initial setup failure issue --- .../xcschemes/xcschememanagement.plist | 6 +-- .../Discovery/DiscoverySection.swift | 7 +++- .../View/Content/ProfileCardView.swift | 39 ++++++++++++------- ...ofileCardTableViewCell+Configuration.swift | 30 ++++++++++++++ .../ProfileCardTableViewCell.swift | 10 +++-- 5 files changed, 71 insertions(+), 21 deletions(-) create mode 100644 MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell+Configuration.swift diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index ae6e6040..55845d58 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 33 + 23 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 32 + 22 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 34 + 24 SuppressBuildableAutocreation diff --git a/Mastodon/Diffiable/Discovery/DiscoverySection.swift b/Mastodon/Diffiable/Discovery/DiscoverySection.swift index 76cc9c03..cab2eb82 100644 --- a/Mastodon/Diffiable/Discovery/DiscoverySection.swift +++ b/Mastodon/Diffiable/Discovery/DiscoverySection.swift @@ -52,13 +52,16 @@ extension DiscoverySection { let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ProfileCardTableViewCell.self), for: indexPath) as! ProfileCardTableViewCell context.managedObjectContext.performAndWait { guard let user = record.object(in: context.managedObjectContext) else { return } - cell.profileCardView.configure(user: user) + cell.configure( + tableView: tableView, + user: user, + profileCardTableViewCellDelegate: configuration.profileCardTableViewCellDelegate + ) } context.authenticationService.activeMastodonAuthentication .map { $0?.user } .assign(to: \.me, on: cell.profileCardView.viewModel.relationshipViewModel) .store(in: &cell.disposeBag) - cell.delegate = configuration.profileCardTableViewCellDelegate return cell case .bottomLoader: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift index 16351ebe..07f44150 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -46,6 +46,8 @@ public final class ProfileCardView: UIView { // author username public let authorUsernameLabel = MetaLabel(style: .profileCardUsername) + // bio + let bioMetaTextAdaptiveMarginContainerView = AdaptiveMarginContainerView() let bioMetaText: MetaText = { let metaText = MetaText() metaText.textView.backgroundColor = .clear @@ -78,6 +80,7 @@ public final class ProfileCardView: UIView { return metaText }() + let infoContainerAdaptiveMarginContainerView = AdaptiveMarginContainerView() let infoContainer = UIStackView() let statusDashboardView = ProfileStatusDashboardView() @@ -194,34 +197,36 @@ extension ProfileCardView { // authorInfoContainer: V - [ authorNameLabel | authorUsernameLabel ] let authorInfoContainer = UIStackView() authorInfoContainer.axis = .vertical - authorInfoContainer.spacing = 2 + // authorInfoContainer.spacing = 2 authorContainer.addArrangedSubview(authorInfoContainer) authorInfoContainer.addArrangedSubview(authorNameLabel) authorInfoContainer.addArrangedSubview(authorUsernameLabel) // bioMetaText - let bioMetaTextAdaptiveMarginContainerView = AdaptiveMarginContainerView() bioMetaTextAdaptiveMarginContainerView.contentView = bioMetaText.textView bioMetaTextAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin bioMetaText.textView.setContentHuggingPriority(.required - 1, for: .vertical) bioMetaText.textView.setContentCompressionResistancePriority(.required - 1, for: .vertical) container.addArrangedSubview(bioMetaTextAdaptiveMarginContainerView) container.setCustomSpacing(16, after: bioMetaTextAdaptiveMarginContainerView) - + // infoContainer: H - [ statusDashboardView | (spacer) | relationshipActionButton ] infoContainer.axis = .horizontal infoContainer.spacing = 8 - let infoContainerAdaptiveMarginContainerView = AdaptiveMarginContainerView() infoContainerAdaptiveMarginContainerView.contentView = infoContainer infoContainerAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin container.addArrangedSubview(infoContainerAdaptiveMarginContainerView) - infoContainer.addArrangedSubview(statusDashboardView) - infoContainer.addArrangedSubview(UIView()) - let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() - infoContainer.addArrangedSubview(relationshipActionButtonShadowContainer) - updateInfoContainerLayout() + infoContainer.addArrangedSubview(statusDashboardView) + let infoContainerSpacer = UIView() + infoContainer.addArrangedSubview(UIView()) + infoContainerSpacer.setContentHuggingPriority(.defaultLow - 100, for: .vertical) + infoContainerSpacer.setContentHuggingPriority(.defaultLow - 100, for: .horizontal) + let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() + relationshipActionButtonShadowContainer.translatesAutoresizingMaskIntoConstraints = false + infoContainer.addArrangedSubview(relationshipActionButtonShadowContainer) + relationshipActionButton.translatesAutoresizingMaskIntoConstraints = false relationshipActionButtonShadowContainer.addSubview(relationshipActionButton) NSLayoutConstraint.activate([ @@ -229,15 +234,15 @@ extension ProfileCardView { relationshipActionButton.leadingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.leadingAnchor), relationshipActionButton.trailingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.trailingAnchor), relationshipActionButton.bottomAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.bottomAnchor), - relationshipActionButton.widthAnchor.constraint(greaterThanOrEqualToConstant: ProfileCardView.friendshipActionButtonSize.width).priority(.required - 1), - relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.required - 2), + relationshipActionButtonShadowContainer.widthAnchor.constraint(greaterThanOrEqualToConstant: ProfileCardView.friendshipActionButtonSize.width).priority(.required - 1), + relationshipActionButtonShadowContainer.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.required - 1), ]) - + let bottomPadding = UIView() bottomPadding.translatesAutoresizingMaskIntoConstraints = false container.addArrangedSubview(bottomPadding) NSLayoutConstraint.activate([ - bottomPadding.heightAnchor.constraint(equalToConstant: 16) + bottomPadding.heightAnchor.constraint(equalToConstant: 16).priority(.required - 10), ]) relationshipActionButton.addTarget(self, action: #selector(ProfileCardView.relationshipActionButtonDidPressed(_:)), for: .touchUpInside) @@ -257,6 +262,14 @@ extension ProfileCardView { } extension ProfileCardView { + public func setupLayoutFrame(_ rect: CGRect) { + frame.size.width = rect.width + bioMetaTextAdaptiveMarginContainerView.frame.size.width = frame.width + bioMetaTextAdaptiveMarginContainerView.contentView?.frame.size.width = frame.width - 2 * bioMetaTextAdaptiveMarginContainerView.margin + infoContainerAdaptiveMarginContainerView.frame.size.width = frame.width + infoContainerAdaptiveMarginContainerView.contentView?.frame.size.width = frame.width - 2 * infoContainerAdaptiveMarginContainerView.margin + } + private func updateInfoContainerLayout() { let isCompactAdaptive = bounds.width < 350 infoContainer.axis = isCompactAdaptive ? .vertical : .horizontal diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell+Configuration.swift new file mode 100644 index 00000000..061af0f4 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell+Configuration.swift @@ -0,0 +1,30 @@ +// +// ProfileCardTableViewCell+Configuration.swift +// +// +// Created by MainasuK on 2022-4-19. +// + +import UIKit +import CoreDataStack + +extension ProfileCardTableViewCell { + + public func configure( + tableView: UITableView, + user: MastodonUser, + profileCardTableViewCellDelegate: ProfileCardTableViewCellDelegate? + ) { + if profileCardView.frame == .zero { + // set content view width + assert(layoutMarginsGuide.layoutFrame.width > .zero) + shadowBackgroundContainer.frame.size.width = layoutMarginsGuide.layoutFrame.width + profileCardView.setupLayoutFrame(layoutMarginsGuide.layoutFrame) + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): did layout for new cell") + } + + profileCardView.configure(user: user) + delegate = profileCardTableViewCellDelegate + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift index 5961ad10..aff7b6fe 100644 --- a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift @@ -5,6 +5,7 @@ // Created by MainasuK on 2022-4-14. // +import os.log import UIKit import Combine @@ -14,9 +15,13 @@ public protocol ProfileCardTableViewCellDelegate: AnyObject { public final class ProfileCardTableViewCell: UITableViewCell { + let logger = Logger(subsystem: "ProfileCardTableViewCell", category: "Cell") + public weak var delegate: ProfileCardTableViewCellDelegate? public var disposeBag = Set() + public let shadowBackgroundContainer = ShadowBackgroundContainer() + public let profileCardView: ProfileCardView = { let profileCardView = ProfileCardView() profileCardView.layer.masksToBounds = true @@ -49,15 +54,14 @@ extension ProfileCardTableViewCell { private func _init() { selectionStyle = .none - let shadowBackgroundContainer = ShadowBackgroundContainer() shadowBackgroundContainer.cornerRadius = 6 shadowBackgroundContainer.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(shadowBackgroundContainer) NSLayoutConstraint.activate([ - shadowBackgroundContainer.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10), + shadowBackgroundContainer.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).priority(.required - 1), shadowBackgroundContainer.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), shadowBackgroundContainer.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), - contentView.bottomAnchor.constraint(equalTo: shadowBackgroundContainer.bottomAnchor, constant: 10), + contentView.bottomAnchor.constraint(equalTo: shadowBackgroundContainer.bottomAnchor, constant: 10).priority(.required - 1), ]) profileCardView.translatesAutoresizingMaskIntoConstraints = false From d70f734957e900f3794c3b27a3480e0a2b8fc57b Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 19 Apr 2022 21:34:49 +0800 Subject: [PATCH 187/188] feat: add discovery intro banner --- Localization/app.json | 3 +- Mastodon.xcodeproj/project.pbxproj | 12 +++ .../Posts/DiscoveryPostsViewController.swift | 25 +++++ .../View/DiscoveryIntroBannerView.swift | 101 ++++++++++++++++++ .../Preference/Preference+Discovery.swift | 19 ++++ 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift create mode 100644 MastodonSDK/Sources/MastodonCommon/Preference/Preference+Discovery.swift diff --git a/Localization/app.json b/Localization/app.json index 6c4aae7a..a8fc9031 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -499,7 +499,8 @@ "hashtags": "Hashtags", "news": "News", "for_you": "For You" - } + }, + "intro": "These are the posts gaining traction in your corner of Mastodon." }, "favorite": { "title": "Your Favorites" diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index d7e76cd3..6686f1e7 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -148,6 +148,7 @@ DB0618072785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618062785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift */; }; DB06180A2785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618092785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift */; }; DB084B5725CBC56C00F898ED /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB084B5625CBC56C00F898ED /* Status.swift */; }; + DB0A322E280EE9FD001729D2 /* DiscoveryIntroBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */; }; DB0AC6FC25CD02E600D75117 /* APIService+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */; }; DB0C946526A6FD4D0088FB11 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB0C946426A6FD4D0088FB11 /* AlamofireImage */; }; DB0C947726A7FE840088FB11 /* NotificationAvatarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */; }; @@ -870,6 +871,7 @@ DB0618062785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonRegisterViewModel+Diffable.swift"; sourceTree = ""; }; DB0618092785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterAvatarTableViewCell.swift; sourceTree = ""; }; DB084B5625CBC56C00F898ED /* Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = ""; }; + DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryIntroBannerView.swift; sourceTree = ""; }; DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Instance.swift"; sourceTree = ""; }; DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationAvatarButton.swift; sourceTree = ""; }; DB0EF72A26FDB1D200347686 /* SidebarListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarListCollectionViewCell.swift; sourceTree = ""; }; @@ -2023,6 +2025,14 @@ path = CoreDataStack; sourceTree = ""; }; + DB0A322F280EEA00001729D2 /* View */ = { + isa = PBXGroup; + children = ( + DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */, + ); + path = View; + sourceTree = ""; + }; DB0C947826A7FE950088FB11 /* Button */ = { isa = PBXGroup; children = ( @@ -3108,6 +3118,7 @@ DBDFF1912805544800557A48 /* Discovery */ = { isa = PBXGroup; children = ( + DB0A322F280EEA00001729D2 /* View */, DBDFF19828055A0900557A48 /* Posts */, DB3E6FDE2806A41200B035AE /* Hashtags */, DB3E6FED2806D7FC00B035AE /* News */, @@ -4085,6 +4096,7 @@ DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */, DB7F48452620241000796008 /* ProfileHeaderViewModel.swift in Sources */, DB647C5926F1EA2700F7F82C /* WizardPreference.swift in Sources */, + DB0A322E280EE9FD001729D2 /* DiscoveryIntroBannerView.swift in Sources */, 2D3F9E0425DFA133004262D9 /* UITapGestureRecognizer.swift in Sources */, 5DDDF1992617447F00311060 /* Mastodon+Entity+Tag.swift in Sources */, 5B90C45F262599800002E742 /* SettingsToggleTableViewCell.swift in Sources */, diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift index 30e2faf9..259b21d3 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift @@ -8,6 +8,7 @@ import os.log import UIKit import Combine +import MastodonUI final class DiscoveryPostsViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { @@ -31,6 +32,8 @@ final class DiscoveryPostsViewController: UIViewController, NeedsDependency, Med }() let refreshControl = UIRefreshControl() + + let discoveryIntroBannerView = DiscoveryIntroBannerView() deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) @@ -60,6 +63,21 @@ extension DiscoveryPostsViewController { tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) + + discoveryIntroBannerView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(discoveryIntroBannerView) + NSLayoutConstraint.activate([ + discoveryIntroBannerView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor), + discoveryIntroBannerView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + discoveryIntroBannerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + ]) + + discoveryIntroBannerView.delegate = self + discoveryIntroBannerView.isHidden = UserDefaults.shared.discoveryIntroBannerNeedsHidden + UserDefaults.shared.publisher(for: \.discoveryIntroBannerNeedsHidden) + .receive(on: DispatchQueue.main) + .assign(to: \.isHidden, on: discoveryIntroBannerView) + .store(in: &disposeBag) tableView.delegate = self viewModel.setupDiffableDataSource( @@ -146,3 +164,10 @@ extension DiscoveryPostsViewController: ScrollViewContainer { tableView } } + +// MARK: - DiscoveryIntroBannerViewDelegate +extension DiscoveryPostsViewController: DiscoveryIntroBannerViewDelegate { + func discoveryIntroBannerView(_ bannerView: DiscoveryIntroBannerView, closeButtonDidPressed button: UIButton) { + UserDefaults.shared.discoveryIntroBannerNeedsHidden = true + } +} diff --git a/Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift b/Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift new file mode 100644 index 00000000..e3e1c454 --- /dev/null +++ b/Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift @@ -0,0 +1,101 @@ +// +// DiscoveryIntroBannerView.swift +// Mastodon +// +// Created by MainasuK on 2022-4-19. +// + +import os.log +import UIKit +import Combine +import MastodonAsset + +public protocol DiscoveryIntroBannerViewDelegate: AnyObject { + func discoveryIntroBannerView(_ bannerView: DiscoveryIntroBannerView, closeButtonDidPressed button: UIButton) +} + +public final class DiscoveryIntroBannerView: UIView { + + let logger = Logger(subsystem: "DiscoveryIntroBannerView", category: "View") + + var _disposeBag = Set() + + public weak var delegate: DiscoveryIntroBannerViewDelegate? + + let label: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 16, weight: .regular)) + label.textColor = Asset.Colors.Label.primary.color + label.text = "These are the posts gaining traction in your corner of Mastodon." // TODO: i18n + label.numberOfLines = 0 + return label + }() + + let closeButton: HitTestExpandedButton = { + let button = HitTestExpandedButton(type: .system) + button.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal) + button.tintColor = Asset.Colors.Label.secondary.color + return button + }() + + public override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension DiscoveryIntroBannerView { + private func _init() { + preservesSuperviewLayoutMargins = true + + setupAppearance(theme: ThemeService.shared.currentTheme.value) + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.setupAppearance(theme: theme) + } + .store(in: &_disposeBag) + + closeButton.translatesAutoresizingMaskIntoConstraints = false + addSubview(closeButton) + NSLayoutConstraint.activate([ + closeButton.topAnchor.constraint(equalTo: topAnchor, constant: 16).priority(.required - 1), + layoutMarginsGuide.trailingAnchor.constraint(equalTo: closeButton.trailingAnchor), + closeButton.heightAnchor.constraint(equalToConstant: 20).priority(.required - 1), + closeButton.widthAnchor.constraint(equalToConstant: 20).priority(.required - 1), + ]) + + label.translatesAutoresizingMaskIntoConstraints = false + addSubview(label) + NSLayoutConstraint.activate([ + label.topAnchor.constraint(equalTo: topAnchor, constant: 16).priority(.required - 1), + label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), + closeButton.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 10), + bottomAnchor.constraint(equalTo: label.bottomAnchor, constant: 16).priority(.required - 1), + ]) + + closeButton.addTarget(self, action: #selector(DiscoveryIntroBannerView.closeButtonDidPressed(_:)), for: .touchUpInside) + } +} + +extension DiscoveryIntroBannerView { + @objc private func closeButtonDidPressed(_ sender: UIButton) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + delegate?.discoveryIntroBannerView(self, closeButtonDidPressed: sender) + } +} + +extension DiscoveryIntroBannerView { + + private func setupAppearance(theme: Theme) { + backgroundColor = theme.systemBackgroundColor + } + +} diff --git a/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Discovery.swift b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Discovery.swift new file mode 100644 index 00000000..0c6a9c54 --- /dev/null +++ b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Discovery.swift @@ -0,0 +1,19 @@ +// +// Preference+Discovery.swift +// +// +// Created by MainasuK on 2022-4-19. +// + +import Foundation + +extension UserDefaults { + + @objc public dynamic var discoveryIntroBannerNeedsHidden: Bool { + get { + return bool(forKey: #function) + } + set { self[#function] = newValue } + } + +} From 7ea26aad9002ffef90db90a37f0ae4e0f5997082 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 19 Apr 2022 21:35:28 +0800 Subject: [PATCH 188/188] chore: update version to 1.3.1 (113) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index a16d6ce2..920eaff8 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 6686f1e7..8b212674 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4737,7 +4737,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4766,7 +4766,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4874,11 +4874,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 112; + DYLIB_CURRENT_VERSION = 113; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4905,11 +4905,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 112; + DYLIB_CURRENT_VERSION = 113; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4934,7 +4934,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4959,7 +4959,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4984,7 +4984,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5009,7 +5009,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5095,7 +5095,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5162,11 +5162,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 112; + DYLIB_CURRENT_VERSION = 113; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5191,7 +5191,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5215,7 +5215,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5240,7 +5240,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5265,7 +5265,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5289,7 +5289,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 55845d58..7d790003 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 23 + 30 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 22 + 31 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 24 + 23 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index aa2be51b..0bd11878 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 112 + 113 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 974ce601..0d11fe1f 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index a16d6ce2..920eaff8 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index a16d6ce2..920eaff8 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 20fbcea3..fa92e4a2 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 1325a348..9ee97c1e 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 NSExtension NSExtensionAttributes