diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 000000000..b849515de --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,48 @@ +--- +name: 🛠️ Feature Request +description: Suggest an idea to help us improve +title: "[Feature]: " +labels: + - "feature_request" + +body: + - type: markdown + attributes: + value: | + **Thanks :heart: for taking the time to fill out this feature request report!** + We kindly ask that you search to see if an issue [already exists](https://github.com/mastodon/mastodon-ios/issues?q=is%3Aissue+sort%3Acreated-desc+) for your feature. + + We are also happy to accept contributions from our users. For more details see [here](https://github.com/mastodon/mastodon-ios/blob/develop/Documentation/CONTRIBUTING.md). + + - type: textarea + attributes: + label: Description + description: | + A clear and concise description of the feature you're interested in. + validations: + required: true + + - type: textarea + attributes: + label: Suggested Solution + description: | + Describe the solution you'd like. A clear and concise description of what you want to happen. + validations: + required: true + + - type: textarea + attributes: + label: Alternatives + description: | + Describe alternatives you've considered. + A clear and concise description of any alternative solutions or features you've considered. + validations: + required: false + + - type: textarea + attributes: + label: Additional Context + description: | + Add any other context about the problem here. + validations: + required: false diff --git a/.github/workflows/develop-build.yml b/.github/workflows/develop-build.yml index ede061098..7dd9ebaab 100644 --- a/.github/workflows/develop-build.yml +++ b/.github/workflows/develop-build.yml @@ -24,7 +24,7 @@ jobs: - name: Install codemagic-cli-tools uses: actions/setup-python@v4 with: - python-version: '3.11' + python-version: '3.10' - run: | pip3 install codemagic-cli-tools - run: | diff --git a/Localization/Localizable.stringsdict b/Localization/Localizable.stringsdict index f8964ca5d..37ce1f032 100644 --- a/Localization/Localizable.stringsdict +++ b/Localization/Localizable.stringsdict @@ -71,7 +71,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -79,15 +79,15 @@ NSStringFormatValueTypeKey ld zero - no characters + no characters left one - 1 character + 1 character left few - %ld characters + %ld characters left many - %ld characters + %ld characters left other - %ld characters + %ld characters left plural.count.followed_by_and_mutual diff --git a/Localization/README.md b/Localization/README.md index 93bf290bc..b44fa350d 100644 --- a/Localization/README.md +++ b/Localization/README.md @@ -27,7 +27,7 @@ If there are new translations, Crowdin pushes new commits to a branch called `l1 To update or add new translations, the workflow is as follows: 1. Merge the PR with `l10n_develop` into `develop`. It's usually called `New Crowdin Updates` -2. Run `update.localization.sh` on your computer. +2. Run `update_localization.sh` on your computer. 3. Commit the changes and push `develop`. [crowdin-mastodon-ios]: https://crowdin.com/project/mastodon-for-ios diff --git a/Localization/StringsConvertor/Intents/input/an.lproj/Intents.strings b/Localization/StringsConvertor/Intents/input/an.lproj/Intents.strings new file mode 100644 index 000000000..597347680 --- /dev/null +++ b/Localization/StringsConvertor/Intents/input/an.lproj/Intents.strings @@ -0,0 +1,51 @@ +"16wxgf" = "Publicar en Mastodon"; + +"751xkl" = "Conteniu de Texto"; + +"CsR7G2" = "Publicar en Mastodon"; + +"HZSGTr" = "Qué conteniu publicar?"; + +"HdGikU" = "Publicación fallida"; + +"KDNTJ4" = "Motivo d'o Fallo"; + +"RHxKOw" = "Ninviar Publicación con conteniu de texto"; + +"RxSqsb" = "Publicación"; + +"WCIR3D" = "Publicar ${content} en Mastodon"; + +"ZKJSNu" = "Publicación"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "Visibilidat"; + +"Zo4jgJ" = "Visibilidat d'o Post"; + +"apSxMG-dYQ5NN" = "I hai ${count} opcions que coinciden con «Publico»."; + +"apSxMG-ehFLjY" = "I hai ${count} opcions que coinciden con «Solo seguidores»."; + +"ayoYEb-dYQ5NN" = "${content}, Publico"; + +"ayoYEb-ehFLjY" = "${content}, Nomás Seguidores"; + +"dUyuGg" = "Publicar en Mastodon"; + +"dYQ5NN" = "Publico"; + +"ehFLjY" = "Solo Seguidores"; + +"gfePDu" = "Publicación fallida. ${failureReason}"; + +"k7dbKQ" = "Publicación ninviada con exito."; + +"oGiqmY-dYQ5NN" = "Nomás per confirmar, querebas «Publico»?"; + +"oGiqmY-ehFLjY" = "Nomás per confirmar, querebas «Nomás seguidores»?"; + +"rM6dvp" = "URL"; + +"ryJLwG" = "Publicación ninviada con exito. "; diff --git a/Localization/StringsConvertor/Intents/input/an.lproj/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/an.lproj/Intents.stringsdict new file mode 100644 index 000000000..9e972ae51 --- /dev/null +++ b/Localization/StringsConvertor/Intents/input/an.lproj/Intents.stringsdict @@ -0,0 +1,38 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + I hai %#@count_option@ coincidencias con «${content}». + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + one + 1 opción + other + %ld opcions + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + I hai %#@count_option@ coincidencias con «${visibility}». + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + one + 1 opción + other + %ld opcions + + + + diff --git a/Localization/StringsConvertor/Intents/input/ca.lproj/Intents.strings b/Localization/StringsConvertor/Intents/input/ca.lproj/Intents.strings index 6b92eb263..c02ac08cf 100644 --- a/Localization/StringsConvertor/Intents/input/ca.lproj/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/ca.lproj/Intents.strings @@ -22,7 +22,7 @@ "ZbSjzC" = "Visibilitat"; -"Zo4jgJ" = "Visibilitat de la Publicació"; +"Zo4jgJ" = "Visibilitat de la publicació"; "apSxMG-dYQ5NN" = "Hi ha ${count} opcions que coincideixen amb ‘Públic’."; @@ -30,9 +30,9 @@ "ayoYEb-dYQ5NN" = "${content}, Públic"; -"ayoYEb-ehFLjY" = "${content}, Només Seguidors"; +"ayoYEb-ehFLjY" = "${content}, Només seguidors"; -"dUyuGg" = "Publicació"; +"dUyuGg" = "Publica a Mastodon"; "dYQ5NN" = "Públic"; diff --git a/Localization/StringsConvertor/Intents/input/cs.lproj/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/cs.lproj/Intents.stringsdict index deea8db12..29249b2cc 100644 --- a/Localization/StringsConvertor/Intents/input/cs.lproj/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/cs.lproj/Intents.stringsdict @@ -25,7 +25,7 @@ There are ${count} options matching ‘${visibility}’. NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${visibility}’. + Existuje %#@count_option@ odpovídající „${visibility}“. count_option NSStringFormatSpecTypeKey diff --git a/Localization/StringsConvertor/Intents/input/cy.lproj/Intents.strings b/Localization/StringsConvertor/Intents/input/cy.lproj/Intents.strings index 6877490ba..11007d059 100644 --- a/Localization/StringsConvertor/Intents/input/cy.lproj/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/cy.lproj/Intents.strings @@ -1,51 +1,51 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "Postio ar Mastodon"; -"751xkl" = "Text Content"; +"751xkl" = "Cynnwys Testun"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "Postio ar Mastodon"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Pa gynnwys i bostio?"; -"HdGikU" = "Posting failed"; +"HdGikU" = "Methwyd postio"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "Rheswm y Gwall"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Cyhoeddi Post â chynnwys testun"; "RxSqsb" = "Post"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "Postio ${content} ar Mastodon"; "ZKJSNu" = "Post"; "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "Preifatrwydd"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "Preifatrwydd Post"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Ceir ${count} opsiwn ar gyfer ‘Cyhoeddus’."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Ceir ${count} opsiwn ar gyfer ‘Dilynwyr yn Unig’."; -"ayoYEb-dYQ5NN" = "${content}, Public"; +"ayoYEb-dYQ5NN" = "${content}, Cyhoeddus"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}, Dilynwyr yn Unig"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "Postio ar Mastodon"; -"dYQ5NN" = "Public"; +"dYQ5NN" = "Cyhoeddus"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "Dilynwyr yn unig"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "Methwyd postio. ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "Cyhoeddwyd y post yn llwyddiannus."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "I gadarnhau, rydych chi am ddewis ‘Cyhoeddus’?"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "I gadarnhau, rydych chi am ddewis ‘Dilynwyr yn Unig’?"; "rM6dvp" = "URL"; -"ryJLwG" = "Post was sent successfully. "; +"ryJLwG" = "Cyhoeddwyd y post yn llwyddiannus. "; diff --git a/Localization/StringsConvertor/Intents/input/cy.lproj/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/cy.lproj/Intents.stringsdict index f273a551d..1f37f6a45 100644 --- a/Localization/StringsConvertor/Intents/input/cy.lproj/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/cy.lproj/Intents.stringsdict @@ -5,7 +5,7 @@ There are ${count} options matching ‘${content}’. - 2 NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${content}’. + Ceir %#@count_option@ ar gyfer '${content}'. count_option NSStringFormatSpecTypeKey @@ -13,23 +13,23 @@ NSStringFormatValueTypeKey %ld zero - %ld options + %ld opsiynau one - 1 option + %ld opsiwn two - %ld options + %ld opsiwn few - %ld options + %ld opsiwn many - %ld options + %ld o opsiynau other - %ld options + %ld o opsiynau There are ${count} options matching ‘${visibility}’. NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${visibility}’. + Ceir %#@count_option@ ar gyfer '${visibility}'. count_option NSStringFormatSpecTypeKey @@ -37,17 +37,17 @@ NSStringFormatValueTypeKey %ld zero - %ld options + %ld opsiynau one - 1 option + %ld opsiwn two - %ld options + %ld opsiwn few - %ld options + %ld opsiwn many - %ld options + %ld o opsiynau other - %ld options + %ld opsiwn diff --git a/Localization/StringsConvertor/Intents/input/de.lproj/Intents.strings b/Localization/StringsConvertor/Intents/input/de.lproj/Intents.strings index fd3fbd40f..5d0056766 100644 --- a/Localization/StringsConvertor/Intents/input/de.lproj/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/de.lproj/Intents.strings @@ -1,12 +1,12 @@ -"16wxgf" = "Auf Mastodon posten"; +"16wxgf" = "Auf Mastodon veröffentlichen"; "751xkl" = "Textinhalt"; -"CsR7G2" = "Auf Mastodon posten"; +"CsR7G2" = "Auf Mastodon veröffentlichen"; -"HZSGTr" = "Welcher Inhalt soll gepostet werden?"; +"HZSGTr" = "Welcher Inhalt soll veröffentlicht werden?"; -"HdGikU" = "Posten fehlgeschlagen"; +"HdGikU" = "Veröffentlichen fehlgeschlagen"; "KDNTJ4" = "Fehlerursache"; diff --git a/Localization/StringsConvertor/Intents/input/he.lproj/Intents.strings b/Localization/StringsConvertor/Intents/input/he.lproj/Intents.strings new file mode 100644 index 000000000..6877490ba --- /dev/null +++ b/Localization/StringsConvertor/Intents/input/he.lproj/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. "; diff --git a/Localization/StringsConvertor/Intents/input/he.lproj/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/he.lproj/Intents.stringsdict new file mode 100644 index 000000000..c88207000 --- /dev/null +++ b/Localization/StringsConvertor/Intents/input/he.lproj/Intents.stringsdict @@ -0,0 +1,46 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${content}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + one + 1 option + two + %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 + one + 1 option + two + %ld options + many + %ld options + other + %ld options + + + + diff --git a/Localization/StringsConvertor/Intents/input/id.lproj/Intents.strings b/Localization/StringsConvertor/Intents/input/id.lproj/Intents.strings index aa86f7bde..e5376e35e 100644 --- a/Localization/StringsConvertor/Intents/input/id.lproj/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/id.lproj/Intents.strings @@ -4,13 +4,13 @@ "CsR7G2" = "Buat Postingan di Mastodon"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Konten apa yang ingin diposting?"; "HdGikU" = "Gagal memposting"; "KDNTJ4" = "Alasan Kegagalan"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Kirim Postingan dengan konten berupa teks"; "RxSqsb" = "Postingan"; @@ -24,9 +24,9 @@ "Zo4jgJ" = "Visibilitas Postingan"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Tidak ada ${count} opsi yang cocok dengan 'Publik'."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Tidak ada ${count} opsi yang cocok dengan 'Untuk Pengikut Saja'."; "ayoYEb-dYQ5NN" = "${content}, Publik"; diff --git a/Localization/StringsConvertor/Intents/input/id.lproj/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/id.lproj/Intents.stringsdict index a14f8b9ff..61779d15c 100644 --- a/Localization/StringsConvertor/Intents/input/id.lproj/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/id.lproj/Intents.stringsdict @@ -5,7 +5,7 @@ There are ${count} options matching ‘${content}’. - 2 NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${content}’. + Ada %#@count_option@ yang cocok dengan ${content}. count_option NSStringFormatSpecTypeKey @@ -13,13 +13,13 @@ NSStringFormatValueTypeKey %ld other - %ld options + %ld opsi There are ${count} options matching ‘${visibility}’. NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${visibility}’. + Ada %#@count_option@ yang cocok dengan ${visibility}. count_option NSStringFormatSpecTypeKey @@ -27,7 +27,7 @@ NSStringFormatValueTypeKey %ld other - %ld options + %ld opsi diff --git a/Localization/StringsConvertor/Intents/input/lv.lproj/Intents.strings b/Localization/StringsConvertor/Intents/input/lv.lproj/Intents.strings index eddd2026f..fdd529eee 100644 --- a/Localization/StringsConvertor/Intents/input/lv.lproj/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/lv.lproj/Intents.strings @@ -1,51 +1,51 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "Publicē Mastodon"; -"751xkl" = "Text Content"; +"751xkl" = "Teksta Saturu"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "Publicē Mastodon"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Kādu saturu publicēt?"; -"HdGikU" = "Posting failed"; +"HdGikU" = "Publicēšana neizdevās"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "Neizdošanās Iemesls"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Sūtīt Ziņu ar teksta saturu"; "RxSqsb" = "Ziņa"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "Publicēt ${content} Mastodon"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "Ziņa"; "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "Redzamība"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "Ziņu Redzamība"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Ir ${count} opcijas, kas atbilst “Publisks”."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Ir ${count} opcijas, kas atbilst “Tikai Sekotājiem”."; -"ayoYEb-dYQ5NN" = "${content}, Public"; +"ayoYEb-dYQ5NN" = "${content}, Publisks"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}, Tikai Sekotājiem"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "Publicē Mastodon"; "dYQ5NN" = "Publisks"; "ehFLjY" = "Tikai sekotājiem"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "Publicēšana neizdevās. ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "Ziņa tika veiksmīgi nosūtīta."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "Tikai apstiprinājumam, tu vēlējies \"Publisks\"?"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "Tikai apstiprinājumam, tu vēlējies \"Tikai Sekotājiem\"?"; "rM6dvp" = "URL"; -"ryJLwG" = "Post was sent successfully. "; +"ryJLwG" = "Ziņa tika veiksmīgi nosūtīta. "; diff --git a/Localization/StringsConvertor/Intents/input/lv.lproj/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/lv.lproj/Intents.stringsdict index 8926678aa..2461fec49 100644 --- a/Localization/StringsConvertor/Intents/input/lv.lproj/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/lv.lproj/Intents.stringsdict @@ -5,7 +5,7 @@ There are ${count} options matching ‘${content}’. - 2 NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${content}’. + Ir %#@count_option@, kas atbilst “${content}”. count_option NSStringFormatSpecTypeKey @@ -13,17 +13,17 @@ NSStringFormatValueTypeKey %ld zero - %ld options + %ld opciju one - 1 option + 1 opcija other - %ld options + %ld opcijas There are ${count} options matching ‘${visibility}’. NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${visibility}’. + Ir %#@count_option@, kas atbilst “${visibility}”. count_option NSStringFormatSpecTypeKey @@ -31,11 +31,11 @@ NSStringFormatValueTypeKey %ld zero - %ld options + %ld izvēles one - 1 option + 1 izvēle other - %ld options + %ld izvēles diff --git a/Localization/StringsConvertor/Intents/input/my.lproj/Intents.strings b/Localization/StringsConvertor/Intents/input/my.lproj/Intents.strings new file mode 100644 index 000000000..8fd6a698c --- /dev/null +++ b/Localization/StringsConvertor/Intents/input/my.lproj/Intents.strings @@ -0,0 +1,51 @@ +"16wxgf" = "Mastodon တွင် ပို့စ်တင်ရန်"; + +"751xkl" = "အကြောင်းအရာ"; + +"CsR7G2" = "Mastodon တွင် ပို့စ်တင်ရန်"; + +"HZSGTr" = "ဘယ်အကြောင်းအရာကို ပို့စ်တင်မလဲ?"; + +"HdGikU" = "ပို့စ်တင််ခြင်း မအောင်မြင်ပါ"; + +"KDNTJ4" = "မအောင်မြင်ရသည့် အကြောင်းပြချက်"; + +"RHxKOw" = "ပို့စ်ကို အကြောင်းအရာနှင့်တကွ တင်ရန်"; + +"RxSqsb" = "ပို့စ်"; + +"WCIR3D" = "${content} ကို Mastodon တွင် ပိုစ့်တင်ရန်"; + +"ZKJSNu" = "ပို့စ်"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "မြင်နိုင်မှု"; + +"Zo4jgJ" = "ပို့်စ်မြင်နိုင်မှု"; + +"apSxMG-dYQ5NN" = "‘Public’ နှင့် ကိုက်ညီသော ရွေးချယ်စရာ ${count} ခု ရှိသည်။"; + +"apSxMG-ehFLjY" = "‘Followers Only’ နှင့် ကိုက်ညီသော ရွေးချယ်စရာ ${count} ခု ရှိသည်။"; + +"ayoYEb-dYQ5NN" = "${content}, အများမြင်"; + +"ayoYEb-ehFLjY" = "${content}, စောင့်ကြည့်သူများ သီးသန့်"; + +"dUyuGg" = "Mastodon တွင် ပို့စ်တင်ရန်"; + +"dYQ5NN" = "အများမြင်"; + +"ehFLjY" = "စောင့်ကြည့်သူများသီးသန့်"; + +"gfePDu" = "ပို့စ်တင််ခြင်း မအောင်မြင်ပါ၊ ${failureReason}"; + +"k7dbKQ" = "ပို့စ်ကို အောင်မြင်စွာ ပို့ခဲ့သည်"; + +"oGiqmY-dYQ5NN" = "\"အများမြင်\" ကို ရွေးမည်် သေချာပါသလား?"; + +"oGiqmY-ehFLjY" = "\"စောင့်ကြည့်သူများသီးသန့်\" ကို ရွေးမည်် သေချာပါသလား?"; + +"rM6dvp" = "URL"; + +"ryJLwG" = "ပို့စ်ကို အောင်မြင်စွာ ပို့ခဲ့သည်"; diff --git a/Localization/StringsConvertor/Intents/input/my.lproj/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/my.lproj/Intents.stringsdict new file mode 100644 index 000000000..577ffd124 --- /dev/null +++ b/Localization/StringsConvertor/Intents/input/my.lproj/Intents.stringsdict @@ -0,0 +1,34 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + ‘${content}’ နှင့် ကိုက်ညီသော ရွေးချယ်စရာ %#@count_option@ ခု ရှိသည်။ + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + other + ရွေးချယ်စရာ %ld ခု + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + ‘${visibility}’ နှင့် ကိုက်ညီသော ရွေးချယ်စရာ %#@count_option@ ခု ရှိသည်။ + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + other + ရွေးချယ်စရာ %ld ခု + + + + diff --git a/Localization/StringsConvertor/Intents/input/uk.lproj/Intents.strings b/Localization/StringsConvertor/Intents/input/uk.lproj/Intents.strings index 6877490ba..ecbc72785 100644 --- a/Localization/StringsConvertor/Intents/input/uk.lproj/Intents.strings +++ b/Localization/StringsConvertor/Intents/input/uk.lproj/Intents.strings @@ -1,51 +1,51 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "Поділитись в Mastodon"; -"751xkl" = "Text Content"; +"751xkl" = "Текстовий вміст"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "Поділитись в Mastodon"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Який зміст допису?"; -"HdGikU" = "Posting failed"; +"HdGikU" = "Помилка при надсиланні"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "Причина помилки"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Надіслати пост із текстом"; -"RxSqsb" = "Post"; +"RxSqsb" = "Допис"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "Опублікувати ${content} на Mastodon"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "Допис"; "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "Видимість"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "Видимість допису"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Знайдено ${count} варіантів, що задовольняють \"Публічні\"."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Знайдено ${count} варіантів, які відповідають \"Тільки для підписників\"."; -"ayoYEb-dYQ5NN" = "${content}, Public"; +"ayoYEb-dYQ5NN" = "${content}, публічний"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}, тільки підписники"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "Поділитись в Mastodon"; -"dYQ5NN" = "Public"; +"dYQ5NN" = "Публічно"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "Тільки для підписників"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "Помилка. ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "Допис успішно відправлено."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "Вам дійсно потрібні \"Публічно\"?"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "Вам дійсно потрібні \"Тільки для підписників\"?"; "rM6dvp" = "URL"; -"ryJLwG" = "Post was sent successfully. "; +"ryJLwG" = "Допис успішно відправлено. "; diff --git a/Localization/StringsConvertor/Intents/input/uk.lproj/Intents.stringsdict b/Localization/StringsConvertor/Intents/input/uk.lproj/Intents.stringsdict index a739f778f..ef8eb5d56 100644 --- a/Localization/StringsConvertor/Intents/input/uk.lproj/Intents.stringsdict +++ b/Localization/StringsConvertor/Intents/input/uk.lproj/Intents.stringsdict @@ -5,7 +5,7 @@ There are ${count} options matching ‘${content}’. - 2 NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${content}’. + Знайдено %#@count_option@ відповідних '${content}. count_option NSStringFormatSpecTypeKey @@ -13,19 +13,19 @@ NSStringFormatValueTypeKey %ld one - 1 option + параметр few - %ld options + %ld параметри many - %ld options + %ld параметрів other - %ld options + %ld параметрів There are ${count} options matching ‘${visibility}’. NSStringLocalizedFormatKey - There are %#@count_option@ matching ‘${visibility}’. + Знайдено %#@count_option@ відповідних '${visibility}. count_option NSStringFormatSpecTypeKey @@ -33,13 +33,13 @@ NSStringFormatValueTypeKey %ld one - 1 option + параметр few - %ld options + %ld параметри many - %ld options + %ld параметрів other - %ld options + %ld параметрів diff --git a/Localization/StringsConvertor/input/Base.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/Base.lproj/Localizable.stringsdict index f8964ca5d..37ce1f032 100644 --- a/Localization/StringsConvertor/input/Base.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/Base.lproj/Localizable.stringsdict @@ -71,7 +71,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -79,15 +79,15 @@ NSStringFormatValueTypeKey ld zero - no characters + no characters left one - 1 character + 1 character left few - %ld characters + %ld characters left many - %ld characters + %ld characters left other - %ld characters + %ld characters left plural.count.followed_by_and_mutual diff --git a/Localization/StringsConvertor/input/Base.lproj/app.json b/Localization/StringsConvertor/input/Base.lproj/app.json index ea046bfbc..963b4aed1 100644 --- a/Localization/StringsConvertor/input/Base.lproj/app.json +++ b/Localization/StringsConvertor/input/Base.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Clean Cache", "message": "Successfully cleaned %s cache." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Create account", "see_more": "See More", "preview": "Preview", + "copy": "Copy", "share": "Share", "share_user": "Share %s", "share_post": "Share Post", @@ -91,11 +97,15 @@ "block_domain": "Block %s", "unblock_domain": "Unblock %s", "settings": "Settings", - "delete": "Delete" + "delete": "Delete", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Home", - "search": "Search", + "search_and_explore": "Search and Explore", "notifications": "Notifications", "profile": "Profile" }, @@ -132,6 +142,8 @@ "sensitive_content": "Sensitive Content", "media_content_warning": "Tap anywhere to reveal", "tap_to_reveal": "Tap to reveal", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Vote", "closed": "Closed" @@ -153,6 +165,7 @@ "show_image": "Show image", "show_gif": "Show GIF", "show_video_player": "Show video player", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,18 @@ "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." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" + }, + "media": { + "accessibility_label": "%s, attachment %d of %d", + "expand_image_hint": "Expands the image. Double-tap and hold to show actions", + "expand_gif_hint": "Expands the GIF. Double-tap and hold to show actions", + "expand_video_hint": "Shows the video player. Double-tap and hold to show actions" } }, "friendship": { @@ -360,7 +385,7 @@ "published": "Published!", "Publishing": "Publishing post...", "accessibility": { - "logo_label": "Logo Button", + "logo_label": "Mastodon", "logo_hint": "Tap to scroll to top and tap again to previous location" } } @@ -444,11 +469,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Add Row", "placeholder": { "label": "Label", @@ -722,6 +751,19 @@ }, "bookmark": { "title": "Bookmarks" + + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/an.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/an.lproj/Localizable.stringsdict new file mode 100644 index 000000000..d7187e039 --- /dev/null +++ b/Localization/StringsConvertor/input/an.lproj/Localizable.stringsdict @@ -0,0 +1,465 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 notificación no leyida + other + %ld notificacions no leyidas + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + Limite de dentrada superau en %#@character_count@ caracters + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 caracter + other + %ld caracters + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + Limite de dentrada restante: %#@character_count@ caracters + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 caracter + other + %ld caracters + + + a11y.plural.count.characters_left + + NSStringLocalizedFormatKey + queda %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 caracter + other + %ld caracters + + + plural.count.followed_by_and_mutual + + NSStringLocalizedFormatKey + %#@names@%#@count_mutual@ + names + + one + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + + + count_mutual + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Seguiu per %1$@ y unatro mutuo + other + Seguiu per %1$@ y %ld mutuos + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + publicación + other + publicacions + + + plural.count.media + + NSStringLocalizedFormatKey + %#@media_count@ + media_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 media + other + %ld media + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 publicación + other + %ld publicacions + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 favorito + other + %ld favoritos + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reblogueo + other + %ld reblogueos + + + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 respuesta + other + %ld respuestas + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 voto + other + %ld votos + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 votante + other + %ld votantes + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 persona charrando + other + %ld personas son charrando d'esto + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 seguindo + other + %ld seguindo + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 seguidor + other + %ld seguidores + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 anyo restante + other + %ld anyos restantes + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 mes restante + other + %ld meses restantes + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 día restante + other + %ld días restantes + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 hora restante + other + %ld horas restantes + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 minuto restant + other + %ld minutos restants + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 segundo restante + other + %ld segundos restantes + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Fa 1 anyo + other + Fa %ld anyos + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Fa 1 mes + other + Fa %ld meses + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Fa 1 día + other + Fa %ld días + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Fa 1 h + other + Fa %ld h + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Fa 1 min + other + Fa %ld min + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Fa 1 s + other + Fa %ld s + + + + diff --git a/Localization/StringsConvertor/input/an.lproj/app.json b/Localization/StringsConvertor/input/an.lproj/app.json new file mode 100644 index 000000000..b0e090cf0 --- /dev/null +++ b/Localization/StringsConvertor/input/an.lproj/app.json @@ -0,0 +1,762 @@ +{ + "common": { + "alerts": { + "common": { + "please_try_again": "Per favor, torna a intentar-lo.", + "please_try_again_later": "Per favor, torna a intentar-lo mas enta debant." + }, + "sign_up_failure": { + "title": "Error en rechistrar-se" + }, + "server_error": { + "title": "Error d'o servidor" + }, + "vote_failure": { + "title": "Voto fallido", + "poll_ended": "La enquesta ha rematau" + }, + "discard_post_content": { + "title": "Descartar borrador", + "message": "Confirma pa descartar lo conteniu d'a publicación." + }, + "publish_post_failure": { + "title": "Error de publicación", + "message": "No s'ha puesto publicar la publicación. Per favor, revise la suya connexión a internet.", + "attachments_message": { + "video_attach_with_photo": "No puetz adchuntar un video a una publicación que ya contiene imachens.", + "more_than_one_video": "No puetz adchuntar mas d'un video." + } + }, + "edit_profile_failure": { + "title": "Error en a Edición d'o Perfil", + "message": "No s'ha puesto editar lo perfil. Per favor, intenta-lo de nuevo." + }, + "sign_out": { + "title": "Zarrar Sesión", + "message": "Yes seguro de que quiers zarrar la sesión?", + "confirm": "Zarrar Sesión" + }, + "block_domain": { + "title": "Yes realment seguro, de verdat, que quiers blocar %s a lo completo? En a mayoría d'os casos, uns pocos bloqueyos u silenciaus concretos son suficients y preferibles. No veyerás conteniu d'ixe dominio y totz los tuyos seguidores d'ixe dominio serán eliminaus.", + "block_entire_domain": "Blocar Dominio" + }, + "save_photo_failure": { + "title": "Error en Alzar Foto", + "message": "Per favor, activa lo permiso d'acceso a la biblioteca de fotos pa alzar la foto." + }, + "delete_post": { + "title": "Yes seguro de que quiers eliminar esta publicación?", + "message": "Yes seguro de que quiers borrar esta publicación?" + }, + "clean_cache": { + "title": "Limpiar Caché", + "message": "S'ha limpiau con exito %s de caché." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" + } + }, + "controls": { + "actions": { + "back": "Dezaga", + "next": "Siguient", + "previous": "Anterior", + "open": "Ubrir", + "add": "Anyadir", + "remove": "Eliminar", + "edit": "Editar", + "save": "Alzar", + "ok": "Acceptar", + "done": "Feito", + "confirm": "Confirmar", + "continue": "Continar", + "compose": "Redactar", + "cancel": "Cancelar", + "discard": "Descartar", + "try_again": "Intenta-lo de nuevo", + "take_photo": "Prener foto", + "save_photo": "Alzar foto", + "copy_photo": "Copiar foto", + "sign_in": "Iniciar sesión", + "sign_up": "Crear cuenta", + "see_more": "Veyer mas", + "preview": "Vista previa", + "copy": "Copy", + "share": "Compartir", + "share_user": "Compartir %s", + "share_post": "Compartir publicación", + "open_in_safari": "Ubrir en Safari", + "open_in_browser": "Ubrir en o navegador", + "find_people": "Troba chent a la quala seguir", + "manually_search": "Millor fer una busqueda manual", + "skip": "Omitir", + "reply": "Responder", + "report_user": "Reportar a %s", + "block_domain": "Blocar %s", + "unblock_domain": "Desbloquiar %s", + "settings": "Configuración", + "delete": "Borrar", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } + }, + "tabs": { + "home": "Inicio", + "search_and_explore": "Search and Explore", + "notifications": "Notificacions", + "profile": "Perfil" + }, + "keyboard": { + "common": { + "switch_to_tab": "Cambiar a %s", + "compose_new_post": "Escribir Nueva Publicación", + "show_favorites": "Amostrar Favoritos", + "open_settings": "Ubrir Configuración" + }, + "timeline": { + "previous_status": "Publicación Anterior", + "next_status": "Siguient Publicación", + "open_status": "Ubrir Publicación", + "open_author_profile": "Ubrir Perfil de l'Autor", + "open_reblogger_profile": "Ubrir Perfil d'o Reblogueador", + "reply_status": "Responder Publicación", + "toggle_reblog": "Commutar lo Reblogueo en a Publicación", + "toggle_favorite": "Commutar la Marca de Favorito en a Publicación", + "toggle_content_warning": "Alternar l'Alvertencia de Conteniu", + "preview_image": "Previsualizar Imachen" + }, + "segmented_control": { + "previous_section": "Sección Anterior", + "next_section": "Siguient Sección" + } + }, + "status": { + "user_reblogged": "%s lo reblogueó", + "user_replied_to": "En respuesta a %s", + "show_post": "Amostrar Publicación", + "show_user_profile": "Amostrar perfil de l'usuario", + "content_warning": "Alvertencia de Conteniu", + "sensitive_content": "Conteniu sensible", + "media_content_warning": "Preta en qualsequier puesto pa amostrar", + "tap_to_reveal": "Tocar pa revelar", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", + "poll": { + "vote": "Vota", + "closed": "Zarrau" + }, + "meta_entity": { + "url": "Vinclo: %s", + "hashtag": "Hashtag: %s", + "mention": "Amostrar lo perfil: %s", + "email": "Adreza de correu: %s" + }, + "actions": { + "reply": "Responder", + "reblog": "Rebloguear", + "unreblog": "Desfer reblogueo", + "favorite": "Favorito", + "unfavorite": "No favorito", + "menu": "Menú", + "hide": "Amagar", + "show_image": "Amostrar imachen", + "show_gif": "Amostrar GIF", + "show_video_player": "Amostrar reproductor de video", + "share_link_in_post": "Share Link in Post", + "tap_then_hold_to_show_menu": "Toca, dimpués mantiene pa amostrar lo menú" + }, + "tag": { + "url": "URL", + "mention": "Mención", + "link": "Vinclo", + "hashtag": "Etiqueta", + "email": "E-mail", + "emoji": "Emoji" + }, + "visibility": { + "unlisted": "Totz pueden veyer este post pero no amostrar-lo en una linia de tiempo publica.", + "private": "Nomás los suyos seguidores pueden veyer este mensache.", + "private_from_me": "Nomás los míos seguidores pueden veyer este mensache.", + "direct": "Nomás l'usuario mencionau puede veyer este mensache." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" + } + }, + "friendship": { + "follow": "Seguir", + "following": "Seguindo", + "request": "Solicitut", + "pending": "Pendient", + "block": "Blocar", + "block_user": "Blocar a %s", + "block_domain": "Blocar a %s", + "unblock": "Desbloquiar", + "unblock_user": "Desbloquiar a %s", + "blocked": "Blocau", + "mute": "Silenciar", + "mute_user": "Silenciar a %s", + "unmute": "Desmutear", + "unmute_user": "Desmutear a %s", + "muted": "Silenciau", + "edit_info": "Editar Info", + "show_reblogs": "Amostrar los retuts", + "hide_reblogs": "Amagar los reblogs" + }, + "timeline": { + "filtered": "Filtrau", + "timestamp": { + "now": "Agora" + }, + "loader": { + "load_missing_posts": "Cargar publicacions faltantes", + "loading_missing_posts": "Cargando publicacions faltantes...", + "show_more_replies": "Amostrar mas respuestas" + }, + "header": { + "no_status_found": "No s'ha trobau garra publicación", + "blocking_warning": "No puetz veyer lo perfil d'este usuario\n dica que lo desbloqueyes.\nLo tuyo perfil se veye asinas pa ell.", + "user_blocking_warning": "No puetz veyer lo perfil de %s\n dica que lo desbloqueyes.\nLo tuyo perfil se veye asinas pa ell.", + "blocked_warning": "No puetz veyer lo perfil d'este usuario\n dica que te desbloqueye.", + "user_blocked_warning": "No puetz veyer lo perfil de %s\n dica que te desbloqueye.", + "suspended_warning": "Este usuario ha estau suspendiu.", + "user_suspended_warning": "La cuenta de %s ha estau suspendida." + } + } + } + }, + "scene": { + "welcome": { + "slogan": "Los retz socials\nde nuevo en as tuyas mans.", + "get_started": "Empecipiar", + "log_in": "Iniciar sesión" + }, + "login": { + "title": "Bienveniu de nuevas", + "subtitle": "Dentrar en o servidor an que creyiés la cuenta.", + "server_search_field": { + "placeholder": "Escribir la URL u buscar lo tuyo servidor" + } + }, + "server_picker": { + "title": "Tría un servidor,\nqualsequier servidor.", + "subtitle": "Tría un servidor basau en a tuya rechión, intereses u uno de proposito cheneral. Podrás seguir connectau con totz en Mastodon, independiement d'o servidor.", + "button": { + "category": { + "all": "Totas", + "all_accessiblity_description": "Categoría: Totas", + "academia": "academicos", + "activism": "activismo", + "food": "minchada", + "furry": "furry", + "games": "chuegos", + "general": "cheneral", + "journalism": "periodismo", + "lgbt": "lgbt", + "regional": "rechional", + "art": "arte", + "music": "mosica", + "tech": "tecnolochía" + }, + "see_less": "Veyer Menos", + "see_more": "Veyer Más" + }, + "label": { + "language": "IDIOMA", + "users": "USUARIOS", + "category": "CATEGORÍA" + }, + "input": { + "search_servers_or_enter_url": "Mirar comunidatz u escribir URL" + }, + "empty_state": { + "finding_servers": "Trobando servidors disponibles...", + "bad_network": "Bella cosa ha iu malament en cargar los datos. Compreba la tuya connexión a Internet.", + "no_results": "Sin resultaus" + } + }, + "register": { + "title": "Deixa que te configuremos en %s", + "lets_get_you_set_up_on_domain": "Deixa que te configuremos en %s", + "input": { + "avatar": { + "delete": "Borrar" + }, + "username": { + "placeholder": "nombre d'usuario", + "duplicate_prompt": "Este nombre d'usuario ya ye en uso." + }, + "display_name": { + "placeholder": "nombre a amostrar" + }, + "email": { + "placeholder": "correu electronico" + }, + "password": { + "placeholder": "clau", + "require": "La tuya clau ha de contener como minimo:", + "character_limit": "8 caracters", + "accessibility": { + "checked": "marcau", + "unchecked": "sin marcar" + }, + "hint": "La tuya clau ameneste tener a lo menos ueito caracters" + }, + "invite": { + "registration_user_invite_request": "Per qué quiers unir-te?" + } + }, + "error": { + "item": { + "username": "Nombre d'usuario", + "email": "Correu electronico", + "password": "Clau", + "agreement": "Acceptación", + "locale": "Idioma", + "reason": "Motivo" + }, + "reason": { + "blocked": "%s contiene un furnidor de correu no permitiu", + "unreachable": "%s pareixe no existir", + "taken": "%s ya ye en uso", + "reserved": "%s ye una parola clau reservada", + "accepted": "%s ha d'estar acceptau", + "blank": "Se requiere %s", + "invalid": "%s no ye valido", + "too_long": "%s ye masiau largo", + "too_short": "%s ye masiau tallo", + "inclusion": "%s no ye una valor admitida" + }, + "special": { + "username_invalid": "Lo nombre d'usuario solo puede contener caracters alfanumericos y guións baixos", + "username_too_long": "Lo nombre d'usuario ye masiau largo (no puede tener mas de 30 caracters)", + "email_invalid": "Esta no ye una adreza de correu electronico valida", + "password_too_short": "La clau ye masiau curta (ha de tener a lo menos 8 caracters)" + } + } + }, + "server_rules": { + "title": "Qualques reglas basicas.", + "subtitle": "Estas reglas son establidas per los administradors de %s.", + "prompt": "Si continas serás sucheto a los termins de servicio y la politica de privacidat de %s.", + "terms_of_service": "termins d'o servicio", + "privacy_policy": "politica de privacidat", + "button": { + "confirm": "Accepto" + } + }, + "confirm_email": { + "title": "Una zaguera coseta.", + "subtitle": "T'acabamos de ninviar un correu a %s, preta en o vinclo pa confirmar la tuya cuenta.", + "tap_the_link_we_emailed_to_you_to_verify_your_account": "Toca lo vinclo que te ninviamos per correu electronico pa verificar la tuya cuenta", + "button": { + "open_email_app": "Ubrir Aplicación de Correu Electronico", + "resend": "Reninviar" + }, + "dont_receive_email": { + "title": "Revisa lo tuyo correu electronico", + "description": "Compreba que la tuya adreza de correu electronico sía correcta y revisa la carpeta de correu no deseyau si no l'has feito ya.", + "resend_email": "Tornar a Ninviar Correu Electronico" + }, + "open_email_app": { + "title": "Revisa la tuya servilla de dentrada.", + "description": "T'acabamos de ninviar un correu electronico. Revisa la tuya carpeta de correu no deseyau si no l'has feito ya.", + "mail": "Correu", + "open_email_client": "Ubrir Client de Correu Electronico" + } + }, + "home_timeline": { + "title": "Inicio", + "navigation_bar_state": { + "offline": "Sin Connexión", + "new_posts": "Veyer nuevas publicacions", + "published": "Publicau!", + "Publishing": "Publicación en curso...", + "accessibility": { + "logo_label": "Botón d'o logo", + "logo_hint": "Toca pa desplazar-te enta alto y toca de nuevo pa la localización anterior" + } + } + }, + "suggestion_account": { + "title": "Troba Chent a la quala Seguir", + "follow_explain": "Quan sigas a belún veyerás las suyas publicacions en a tuya pachina d'inicio." + }, + "compose": { + "title": { + "new_post": "Nueva Publicación", + "new_reply": "Nueva Respuesta" + }, + "media_selection": { + "camera": "Fer Foto", + "photo_library": "Galería de Fotos", + "browse": "Explorar" + }, + "content_input_placeholder": "Escribe u apega lo que tiengas en mente", + "compose_action": "Publicar", + "replying_to_user": "en respuesta a %s", + "attachment": { + "photo": "foto", + "video": "video", + "attachment_broken": "Este %s ye roto y no puede\npuyar-se a Mastodon.", + "description_photo": "Describe la foto pa los usuarios con dificultat visual...", + "description_video": "Describe lo video pa los usuarios con dificultat visual...", + "load_failed": "Fallo de carga", + "upload_failed": "Fallo de carga", + "can_not_recognize_this_media_attachment": "No se puede reconocer este adchunto multimedia", + "attachment_too_large": "Adchunto masiau gran", + "compressing_state": "Comprimindo...", + "server_processing_state": "Lo servidor ye procesando..." + }, + "poll": { + "duration_time": "Duración: %s", + "thirty_minutes": "30 minutos", + "one_hour": "1 Hora", + "six_hours": "6 Horas", + "one_day": "1 Día", + "three_days": "3 Días", + "seven_days": "7 Días", + "option_number": "Opción %ld", + "the_poll_is_invalid": "La enquesta ye invalida", + "the_poll_has_empty_option": "La enquesta tiene opcions vuedas" + }, + "content_warning": { + "placeholder": "Escribe una alvertencia precisa aquí..." + }, + "visibility": { + "public": "Publica", + "unlisted": "Sin listar", + "private": "Solo seguidores", + "direct": "Solo la chent que yo menciono" + }, + "auto_complete": { + "space_to_add": "Espacio pa anyadir" + }, + "accessibility": { + "append_attachment": "Anyadir Adchunto", + "append_poll": "Anyadir Enqüesta", + "remove_poll": "Eliminar Enqüesta", + "custom_emoji_picker": "Selector de Emojis Personalizaus", + "enable_content_warning": "Activar Alvertencia de Conteniu", + "disable_content_warning": "Desactivar Alvertencia de Conteniu", + "post_visibility_menu": "Menú de Visibilidat d'a Publicación", + "post_options": "Opcions d'o tut", + "posting_as": "Publicando como %s" + }, + "keyboard": { + "discard_post": "Descartar Publicación", + "publish_post": "Publicar", + "toggle_poll": "Commutar Enqüesta", + "toggle_content_warning": "Commutar Alvertencia de Conteniu", + "append_attachment_entry": "Anyadir Adchunto - %s", + "select_visibility_entry": "Triar Visibilidat - %s" + } + }, + "profile": { + "header": { + "follows_you": "Te sigue" + }, + "dashboard": { + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" + }, + "fields": { + "joined": "Joined", + "add_row": "Anyadir Ringlera", + "placeholder": { + "label": "Nombre pa lo campo", + "content": "Conteniu" + }, + "verified": { + "short": "Verificau en %s", + "long": "La propiedat d'este vinclo ha estau verificada lo %s" + } + }, + "segmented_control": { + "posts": "Publicacions", + "replies": "Respuestas", + "posts_and_replies": "Publicacions y respuestas", + "media": "Multimedia", + "about": "Sobre" + }, + "relationship_action_alert": { + "confirm_mute_user": { + "title": "Silenciar cuenta", + "message": "Confirmar pa silenciar %s" + }, + "confirm_unmute_user": { + "title": "Deixar de Silenciar Cuenta", + "message": "Confirmar pa deixar de silenciar a %s" + }, + "confirm_block_user": { + "title": "Blocar cuenta", + "message": "Confirmar pa blocar a %s" + }, + "confirm_unblock_user": { + "title": "Desbloquiar cuenta", + "message": "Confirmar pa desbloquiar a %s" + }, + "confirm_show_reblogs": { + "title": "Amostrar los reblogs", + "message": "Confimrar pa amostrar los reblogs" + }, + "confirm_hide_reblogs": { + "title": "Amagar los reblogs", + "message": "Comfirmar pa amagar los reblogs" + } + }, + "accessibility": { + "show_avatar_image": "Amostrar imachen d'o avatar", + "edit_avatar_image": "Editar imachen d'o avatar", + "show_banner_image": "Amostrar imachen de banner", + "double_tap_to_open_the_list": "Preta dos vegadas pa ubrir la lista" + } + }, + "follower": { + "title": "seguidor", + "footer": "No s'amuestran los seguidores d'atros servidors." + }, + "following": { + "title": "seguindo", + "footer": "No s'amuestran los seguius d'atros servidors." + }, + "familiarFollowers": { + "title": "Seguidores que conoixes", + "followed_by_names": "Seguiu per %s" + }, + "favorited_by": { + "title": "Feito favorito per" + }, + "reblogged_by": { + "title": "Reblogueado per" + }, + "search": { + "title": "Buscar", + "search_bar": { + "placeholder": "Buscar etiquetas y usuarios", + "cancel": "Cancelar" + }, + "recommend": { + "button_text": "Veyer Totas", + "hash_tag": { + "title": "Tendencias en Mastodon", + "description": "Etiquetas que son recibindo pro atención", + "people_talking": "%s personas son charrando d'esto" + }, + "accounts": { + "title": "Cuentas que talment quieras seguir", + "description": "Puede que faiga goyo seguir estas cuentas", + "follow": "Seguir" + } + }, + "searching": { + "segment": { + "all": "Tot", + "people": "Chent", + "hashtags": "Etiquetas", + "posts": "Publicacions" + }, + "empty_state": { + "no_results": "Sin resultaus" + }, + "recent_search": "Busquedas recients", + "clear": "Borrar" + } + }, + "discovery": { + "tabs": { + "posts": "Publicacions", + "hashtags": "Etiquetas", + "news": "Noticias", + "community": "Comunidat", + "for_you": "Pa Tu" + }, + "intro": "Estas son las publicacions que son ganando tracción en a tuya rincón de Mastodon." + }, + "favorite": { + "title": "Los tuyos Favoritos" + }, + "notification": { + "title": { + "Everything": "Tot", + "Mentions": "Mencions" + }, + "notification_description": { + "followed_you": "te siguió", + "favorited_your_post": "ha marcau como favorita la tuya publicación", + "reblogged_your_post": "reblogueó la tuya publicación", + "mentioned_you": "te mencionó", + "request_to_follow_you": "solicitó seguir-te", + "poll_has_ended": "enqüesta ha rematau" + }, + "keyobard": { + "show_everything": "Amostrar Tot", + "show_mentions": "Amostrar Mencions" + }, + "follow_request": { + "accept": "Acceptar", + "accepted": "Acceptau", + "reject": "refusar", + "rejected": "Refusau" + } + }, + "thread": { + "back_title": "Publicación", + "title": "Publicación de %s" + }, + "settings": { + "title": "Configuración", + "section": { + "appearance": { + "title": "Apariencia", + "automatic": "Automatica", + "light": "Siempre Clara", + "dark": "Siempre Fosca" + }, + "look_and_feel": { + "title": "Apariencia", + "use_system": "Uso d'o sistema", + "really_dark": "Realment Fosco", + "sorta_dark": "Más u Menos Fosco", + "light": "Claro" + }, + "notifications": { + "title": "Notificacions", + "favorites": "Marque como favorita la mía publicación", + "follows": "me siga", + "boosts": "Rebloguee la mía publicación", + "mentions": "me mencione", + "trigger": { + "anyone": "qualsequiera", + "follower": "un seguidor", + "follow": "qualsequiera que yo siga", + "noone": "dengún", + "title": "Recibir notificación quan" + } + }, + "preference": { + "title": "Preferencias", + "true_black_dark_mode": "Modo fosco negro real", + "disable_avatar_animation": "Deshabilitar avatares animaus", + "disable_emoji_animation": "Deshabilitar emojis animaus", + "using_default_browser": "Usar navegador predeterminau pa ubrir los vinclos", + "open_links_in_mastodon": "Ubrir links en Mastodon" + }, + "boring_zone": { + "title": "La Zona Aburrida", + "account_settings": "Configuración de Cuenta", + "terms": "Termins de Servicio", + "privacy": "Politica de Privacidat" + }, + "spicy_zone": { + "title": "La Zona Picante", + "clear": "Borrar Caché de Multimedia", + "signout": "Zarrar Sesión" + } + }, + "footer": { + "mastodon_description": "Mastodon ye software de codigo ubierto. Puetz informar d'errors en GitHub en %s (%s)" + }, + "keyboard": { + "close_settings_window": "Zarrar Finestra de Configuración" + } + }, + "report": { + "title_report": "Reportar", + "title": "Reportar %s", + "step1": "Paso 1 de 2", + "step2": "Paso 2 de 2", + "content1": "I hai belatra publicación que te fería goyo d'anyadir a lo reporte?", + "content2": "I hai bella cosa que los moderadors habrían de saber sobre este reporte?", + "report_sent_title": "Gracias per denunciar, estudiaremos esto.", + "send": "Ninviar Denuncia", + "skip_to_send": "Ninviar sin comentarios", + "text_placeholder": "Escribe u apega comentarios adicionals", + "reported": "DENUNCIAU", + "step_one": { + "step_1_of_4": "Paso 1 de 4", + "whats_wrong_with_this_post": "Qué i hai de malo con esta publicación?", + "whats_wrong_with_this_account": "Qué i hai de malo con esta cuenta?", + "whats_wrong_with_this_username": "Qué i hai de malo con %s?", + "select_the_best_match": "Tría la millor opción", + "i_dont_like_it": "No me fa goyo", + "it_is_not_something_you_want_to_see": "No ye bella cosa que quieras veyer", + "its_spam": "Ye spam", + "malicious_links_fake_engagement_or_repetetive_replies": "Vinclos maliciosos, compromisos falsos u respuestas repetitivas", + "it_violates_server_rules": "Viola las reglas d'o servidor", + "you_are_aware_that_it_breaks_specific_rules": "Yes conscient de que infrinche las normas especificas", + "its_something_else": "Ye bella cosa mas", + "the_issue_does_not_fit_into_other_categories": "Lo problema no encaixa en atras categorías" + }, + "step_two": { + "step_2_of_4": "Paso 2 de 4", + "which_rules_are_being_violated": "Qué normas se son violando?", + "select_all_that_apply": "Tría totz los que correspondan", + "i_just_don’t_like_it": "Nomás no me fa goyo" + }, + "step_three": { + "step_3_of_4": "Paso 3 de 4", + "are_there_any_posts_that_back_up_this_report": "I hai bella publicación que refirme este informe?", + "select_all_that_apply": "Tría totz los que correspondan" + }, + "step_four": { + "step_4_of_4": "Paso 4 de 4", + "is_there_anything_else_we_should_know": "I hai bella cosa mas que habríanos de saber?" + }, + "step_final": { + "dont_want_to_see_this": "No quiers veyer esto?", + "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "Quan veigas bella cosa que no te fa goyo en Mastodon, puetz sacar a la persona d'a tuya experiencia.", + "unfollow": "Deixar de seguir", + "unfollowed": "Ha deixau de seguir-te", + "unfollow_user": "Deixar de seguir a %s", + "mute_user": "Silenciar a %s", + "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "No veyerás las suyas publicacions u reblogueos en a tuya linia temporal. No sabrán que han estau silenciaus.", + "block_user": "Blocar a %s", + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "Ya no podrán estar capaces de seguir-te u veyer las tuyas publicacions, pero pueden veyer si han estau blocaus.", + "while_we_review_this_you_can_take_action_against_user": "Mientres revisamos esto, puetz prener medidas contra %s" + } + }, + "preview": { + "keyboard": { + "close_preview": "Zarrar Previsualización", + "show_next": "Amostrar Siguient", + "show_previous": "Amostrar Anterior" + } + }, + "account_list": { + "tab_bar_hint": "Perfil triau actualment: %s. Fe un doble toque y mantiene pretau pa amostrar lo selector de cuentas", + "dismiss_account_switcher": "Descartar lo selector de cuentas", + "add_account": "Anyadir cuenta" + }, + "wizard": { + "new_in_mastodon": "Nuevo en Mastodon", + "multiple_account_switch_intro_description": "Cambie entre quantas cuentas mantenendo presionado lo botón de perfil.", + "accessibility_hint": "Fe doble toque pa descartar este asistent" + }, + "bookmark": { + "title": "Marcapachinas" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } + } + } +} diff --git a/Localization/StringsConvertor/input/an.lproj/ios-infoPlist.json b/Localization/StringsConvertor/input/an.lproj/ios-infoPlist.json new file mode 100644 index 000000000..a493d53d9 --- /dev/null +++ b/Localization/StringsConvertor/input/an.lproj/ios-infoPlist.json @@ -0,0 +1,6 @@ +{ + "NSCameraUsageDescription": "S'usa pa quitar fotos pa las publicacions", + "NSPhotoLibraryAddUsageDescription": "S'usa pa alzar fotos en a Galería de Fotos", + "NewPostShortcutItemTitle": "Nueva Publicación", + "SearchShortcutItemTitle": "Buscar" +} diff --git a/Localization/StringsConvertor/input/ar.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/ar.lproj/Localizable.stringsdict index 91368a4fb..35727c0d6 100644 --- a/Localization/StringsConvertor/input/ar.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ar.lproj/Localizable.stringsdict @@ -77,7 +77,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + يتبقى %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -91,9 +91,9 @@ two حَرفانِ اِثنان few - %ld characters + %ld أحرُف many - %ld characters + %ld حَرفًا other %ld حَرف diff --git a/Localization/StringsConvertor/input/ar.lproj/app.json b/Localization/StringsConvertor/input/ar.lproj/app.json index bf4bf454e..c27cf8b70 100644 --- a/Localization/StringsConvertor/input/ar.lproj/app.json +++ b/Localization/StringsConvertor/input/ar.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "مَحوُ ذاكِرَةِ التَّخزينِ المُؤقَّت", "message": "مُحِيَ ما مَساحَتُهُ %s مِن ذاكِرَةِ التَّخزينِ المُؤقَّت بِنجاح." + }, + "translation_failed": { + "title": "مُلاحظة", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "حسنًا" } }, "controls": { @@ -75,9 +80,10 @@ "save_photo": "حفظ الصورة", "copy_photo": "نسخ الصورة", "sign_in": "تسجيلُ الدخول", - "sign_up": "Create account", + "sign_up": "إنشاءُ حِساب", "see_more": "عرض المزيد", "preview": "مُعاينة", + "copy": "نَسخ", "share": "المُشارك", "share_user": "مُشارَكَةُ %s", "share_post": "مشارك المنشور", @@ -91,12 +97,16 @@ "block_domain": "حظر %s", "unblock_domain": "رفع الحظر عن %s", "settings": "الإعدادات", - "delete": "حذف" + "delete": "حذف", + "translate_post": { + "title": "الترجَمَة مِن %s", + "unknown_language": "غير مَعرُوفة" + } }, "tabs": { "home": "الرَّئِيسَة", - "search": "البَحث", - "notification": "الإشعارات", + "search_and_explore": "البَحث وَالاِستِكشاف", + "notifications": "الإشعارات", "profile": "المِلَفُّ التَّعريفِيّ" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "مُحتَوى حَسَّاس", "media_content_warning": "اُنقُر لِلكَشف", "tap_to_reveal": "اُنقُر لِلكَشف", + "load_embed": "تحميل المُضمَن", + "link_via_user": "%s via %s", "poll": { "vote": "صَوِّت", "closed": "انتهى" @@ -153,6 +165,7 @@ "show_image": "أظْهِرِ الصُّورَة", "show_gif": "أظْهِر GIF", "show_video_player": "أظْهِر مُشَغِّلَ المَقاطِعِ المَرئِيَّة", + "share_link_in_post": "مُشارَكَة الرابِط فِي مَنشور", "tap_then_hold_to_show_menu": "اُنقُر مُطَوَّلًا لِإظْهَارِ القائِمَة" }, "tag": { @@ -168,6 +181,12 @@ "private": "فَقَطْ مُتابِعينَهُم مَن يُمكِنُهُم رُؤيَةُ هَذَا المَنشُور.", "private_from_me": "فَقَطْ مُتابِعيني أنَا مَن يُمكِنُهُم رُؤيَةُ هَذَا المَنشُور.", "direct": "المُستخدمِونَ المُشارِ إليهم فَقَطْ مَن يُمكِنُهُم رُؤيَةُ هَذَا المَنشُور." + }, + "translation": { + "translated_from": "الترجَمَة مِن %s بِاستِخدَام %s", + "unknown_language": "غير مَعرُوفة", + "unknown_provider": "غير مَعرُوف", + "show_original": "Shown Original" } }, "friendship": { @@ -219,15 +238,15 @@ "log_in": "تسجيلُ الدخول" }, "login": { - "title": "Welcome back", - "subtitle": "Log you in on the server you created your account on.", + "title": "مَرحَبًا بِكَ مُجَدَّدًا", + "subtitle": "سَجِّل دُخولَكَ إلى الخادِم الَّذي أنشأتَ حِسابَكَ فيه.", "server_search_field": { - "placeholder": "Enter URL or search for your server" + "placeholder": "أدخِل عُنوانَ URL أو اِبحَث عَنِ الخادِمِ الخاصّ بِك" } }, "server_picker": { "title": "اِختر خادِم،\nأيًّا مِنهُم.", - "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.", + "subtitle": "اِختر خادمًا بناءً على منطقتك، اِهتماماتك أو يُمكنك حتى اِختيارُ مجتمعٍ ذِي غرضٍ عام. بِإمكانِكَ الدردشة مع أي شخص على مَاستودُون، بغض النظر عن الخادم الخاصة بك.", "button": { "category": { "all": "الكُل", @@ -254,7 +273,7 @@ "category": "الفئة" }, "input": { - "search_servers_or_enter_url": "Search communities or enter URL" + "search_servers_or_enter_url": "اِبحث عَن مُجتَمَعَات أو أدخِل عُنوانَ URL" }, "empty_state": { "finding_servers": "يجري إيجاد خوادم متوفِّرَة...", @@ -427,7 +446,7 @@ "enable_content_warning": "تفعيل تحذير المُحتَوى", "disable_content_warning": "تعطيل تحذير المُحتَوى", "post_visibility_menu": "قائمة ظهور المنشور", - "post_options": "Post Options", + "post_options": "خياراتُ المَنشور", "posting_as": "نَشر كَـ %s" }, "keyboard": { @@ -444,11 +463,15 @@ "follows_you": "يُتابِعُك" }, "dashboard": { - "posts": "مَنشورات", - "following": "مُتابَع", - "followers": "مُتابِع" + "my_posts": "مَنشورات", + "my_following": "مُتابَعُون", + "my_followers": "مُتابِعُون", + "other_posts": "مَنشورات", + "other_following": "مُتابَعُون", + "other_followers": "مُتابِعُون" }, "fields": { + "joined": "Joined", "add_row": "إضافة صف", "placeholder": { "label": "التسمية", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "العَلاماتُ المَرجعيَّة" + }, + "followed_tags": { + "title": "وُسُومُ المُتابَع", + "header": { + "posts": "مَنشورات", + "participants": "المُشارِكُون", + "posts_today": "مَنشوراتُ اليَوم" + }, + "actions": { + "follow": "مُتابَعَة", + "unfollow": "إلغاءُ المُتابَعَة" + } } } } diff --git a/Localization/StringsConvertor/input/ca.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/ca.lproj/Localizable.stringsdict index 947597417..615fd0c48 100644 --- a/Localization/StringsConvertor/input/ca.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ca.lproj/Localizable.stringsdict @@ -408,7 +408,7 @@ NSStringFormatValueTypeKey ld one - fa 1 día + fa 1 dia other fa %ld dies @@ -424,7 +424,7 @@ NSStringFormatValueTypeKey ld one - fa 1h + fa 1 h other fa %ld hores @@ -440,9 +440,9 @@ NSStringFormatValueTypeKey ld one - fa 1 minut + fa 1 min other - fa %ld minuts + fa %ld min date.second.ago.abbr @@ -456,9 +456,9 @@ NSStringFormatValueTypeKey ld one - fa 1 segon + fa 1 s other - fa %ld segons + fa %ld s diff --git a/Localization/StringsConvertor/input/ca.lproj/app.json b/Localization/StringsConvertor/input/ca.lproj/app.json index 52bb67c77..3222ec984 100644 --- a/Localization/StringsConvertor/input/ca.lproj/app.json +++ b/Localization/StringsConvertor/input/ca.lproj/app.json @@ -2,55 +2,60 @@ "common": { "alerts": { "common": { - "please_try_again": "Si us plau intenta-ho de nou.", - "please_try_again_later": "Si us plau, prova-ho més tard." + "please_try_again": "Torna-ho a provar.", + "please_try_again_later": "Prova-ho més tard." }, "sign_up_failure": { "title": "Error en el registre" }, "server_error": { - "title": "Error del Servidor" + "title": "Error del servidor" }, "vote_failure": { - "title": "Error del Vot", + "title": "Error en votar", "poll_ended": "L'enquesta ha finalitzat" }, "discard_post_content": { "title": "Descarta l'esborrany", - "message": "Confirma per a descartar el contingut de la publicació composta." + "message": "Confirma per a descartar el contingut de la publicació." }, "publish_post_failure": { - "title": "Error de Publicació", - "message": "No s'ha pogut enviar la publicació.\nComprova la teva connexió a Internet.", + "title": "Error en publicar", + "message": "No s'ha pogut enviar la publicació.\nComprova la connexió a Internet.", "attachments_message": { "video_attach_with_photo": "No es pot adjuntar un vídeo a una publicació que ja contingui imatges.", - "more_than_one_video": "No pots adjuntar més d'un vídeo." + "more_than_one_video": "No es pot adjuntar més d'un vídeo." } }, "edit_profile_failure": { - "title": "Error al Editar el Perfil", - "message": "No es pot editar el perfil. Si us plau torna-ho a provar." + "title": "Error en editar el perfil", + "message": "No es pot editar el perfil. Torna-ho a provar." }, "sign_out": { - "title": "Tancar Sessió", - "message": "Estàs segur que vols tancar la sessió?", - "confirm": "Tancar Sessió" + "title": "Tanca la sessió", + "message": "Segur que vols tancar la sessió?", + "confirm": "Tanca la sessió" }, "block_domain": { - "title": "Estàs segur, realment segur que vols bloquejar totalment %s? En la majoria dels casos bloquejar o silenciar uns pocs objectius és suficient i preferible. No veureu contingut d’aquest domini i se suprimirà qualsevol dels vostres seguidors d’aquest domini.", - "block_entire_domain": "Bloquejar Domini" + "title": "Estàs totalment segur que vols bloquejar per complet %s? En la majoria dels casos bloquejar o silenciar uns pocs objectius és suficient i preferible. No veureu contingut d’aquest domini i se suprimirà qualsevol dels vostres seguidors d’aquest domini.", + "block_entire_domain": "Bloca el domini" }, "save_photo_failure": { - "title": "Error al Desar la Foto", - "message": "Activa el permís d'accés a la biblioteca de fotos per desar-la." + "title": "Error en desar la foto", + "message": "Activa el permís d'accés a la biblioteca de fotos per a desar-la." }, "delete_post": { - "title": "Esborrar Publicació", - "message": "Estàs segur que vols suprimir aquesta publicació?" + "title": "Eliminar la publicació", + "message": "Segur que vols eliminar aquesta publicació?" }, "clean_cache": { "title": "Neteja la memòria cau", "message": "S'ha netejat correctament la memòria cau de %s." + }, + "translation_failed": { + "title": "Nota", + "message": "La traducció ha fallat. Potser l'administrador d'aquest servidor no ha activat les traduccions o està executant una versió vella de Mastodon on les traduccions encara no eren suportades.", + "button": "D'acord" } }, "controls": { @@ -67,20 +72,21 @@ "done": "Fet", "confirm": "Confirma", "continue": "Continua", - "compose": "Composa", + "compose": "Redacta", "cancel": "Cancel·la", "discard": "Descarta", "try_again": "Torna a provar", "take_photo": "Fes una foto", "save_photo": "Desa la foto", "copy_photo": "Copia la foto", - "sign_in": "Iniciar sessió", + "sign_in": "Inicia sessió", "sign_up": "Crea un compte", - "see_more": "Veure més", + "see_more": "Mostra'n més", "preview": "Vista prèvia", + "copy": "Copia", "share": "Comparteix", - "share_user": "Compartir %s", - "share_post": "Compartir Publicació", + "share_user": "Comparteix %s", + "share_post": "Comparteix la publicació", "open_in_safari": "Obrir a Safari", "open_in_browser": "Obre al navegador", "find_people": "Busca persones a seguir", @@ -91,12 +97,16 @@ "block_domain": "Bloqueja %s", "unblock_domain": "Desbloqueja %s", "settings": "Configuració", - "delete": "Suprimeix" + "delete": "Suprimeix", + "translate_post": { + "title": "Traduït del %s", + "unknown_language": "Desconegut" + } }, "tabs": { "home": "Inici", - "search": "Cerca", - "notification": "Notificació", + "search_and_explore": "Cerca i Explora", + "notifications": "Notificacions", "profile": "Perfil" }, "keyboard": { @@ -110,9 +120,9 @@ "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ó", + "open_author_profile": "Obre el perfil de l'autor", + "open_reblogger_profile": "Obre el perfil de l'impuls", + "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", @@ -132,27 +142,30 @@ "sensitive_content": "Contingut sensible", "media_content_warning": "Toca qualsevol lloc per a mostrar", "tap_to_reveal": "Toca per a mostrar", + "load_embed": "Carregar incrustat", + "link_via_user": "%s través de %s", "poll": { "vote": "Vota", "closed": "Finalitzada" }, "meta_entity": { "url": "Enllaç: %s", - "hashtag": "Etiqueta %s", - "mention": "Mostra el Perfil: %s", + "hashtag": "Etiqueta: %s", + "mention": "Mostra el perfil: %s", "email": "Correu electrònic: %s" }, "actions": { "reply": "Respon", - "reblog": "Impuls", - "unreblog": "Desfer l'impuls", + "reblog": "Impulsa", + "unreblog": "Desfés l'impuls", "favorite": "Favorit", - "unfavorite": "Desfer Favorit", + "unfavorite": "Desfés el favorit", "menu": "Menú", "hide": "Amaga", "show_image": "Mostra la imatge", "show_gif": "Mostra el GIF", "show_video_player": "Mostra el reproductor de vídeo", + "share_link_in_post": "Compartir l'Enllaç en el Tut", "tap_then_hold_to_show_menu": "Toca i manté per a veure el menú" }, "tag": { @@ -161,26 +174,32 @@ "link": "Enllaç", "hashtag": "Etiqueta", "email": "Correu electrònic", - "emoji": "Emoji" + "emoji": "Emojis" }, "visibility": { - "unlisted": "Tothom pot veure aquesta publicació però no es mostra en la línia de temps pública.", + "unlisted": "Tothom pot veure aquesta publicació, però no es mostra en la línia de temps pública.", "private": "Només els seus seguidors poden veure aquesta publicació.", "private_from_me": "Només els meus seguidors poden veure aquesta publicació.", "direct": "Només l'usuari mencionat pot veure aquesta publicació." + }, + "translation": { + "translated_from": "Traduït del %s fent servir %s", + "unknown_language": "Desconegut", + "unknown_provider": "Desconegut", + "show_original": "Mostra l'original" } }, "friendship": { "follow": "Segueix", "following": "Seguint", - "request": "Petició", + "request": "Sol·licitud", "pending": "Pendent", - "block": "Bloqueja", - "block_user": "Bloqueja %s", - "block_domain": "Bloqueja %s", - "unblock": "Desbloqueja", - "unblock_user": "Desbloqueja %s", - "blocked": "Bloquejat", + "block": "Bloca", + "block_user": "Bloca %s", + "block_domain": "Bloca %s", + "unblock": "Desbloca", + "unblock_user": "Desbloca %s", + "blocked": "Blocat", "mute": "Silencia", "mute_user": "Silencia %s", "unmute": "Deixa de silenciar", @@ -196,16 +215,16 @@ "now": "Ara" }, "loader": { - "load_missing_posts": "Carrega les publicacions faltants", - "loading_missing_posts": "Carregant les publicacions faltants...", + "load_missing_posts": "Carrega les publicacions restants", + "loading_missing_posts": "Carregant les publicacions restants...", "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\nfins que et desbloquegi.", - "user_blocked_warning": "No pots veure el perfil de %s\n fins que et desbloquegi.", + "blocking_warning": "No pots veure el perfil d'aquest usuari\nfins que el desbloquis.\nEl teu perfil els sembla així.", + "user_blocking_warning": "No pots veure el perfil de %s\nfins que el desbloquis.\nEl teu perfil els sembla així.", + "blocked_warning": "No pots veure el perfil d'aquest usuari\nfins que et desbloqui.", + "user_blocked_warning": "No pots veure el perfil de %s\n fins que et desbloqui.", "suspended_warning": "Aquest usuari ha estat suspès.", "user_suspended_warning": "El compte de %s ha estat suspès." } @@ -226,7 +245,7 @@ } }, "server_picker": { - "title": "Mastodon està fet d'usuaris en diferents comunitats.", + "title": "Mastodon està fet d'usuaris en diferents servidors.", "subtitle": "Tria un servidor en funció de la teva regió, interessos o un de propòsit general. Seguiràs podent connectar amb tothom a Mastodon, independentment del servidor.", "button": { "category": { @@ -367,11 +386,11 @@ }, "suggestion_account": { "title": "Cerca Persones a Seguir", - "follow_explain": "Quan segueixes algú, veuràs les seves publicacions a Inici." + "follow_explain": "Quan segueixes algú, veuràs els seus tuts a Inici." }, "compose": { "title": { - "new_post": "Nova publicació", + "new_post": "Nou Tut", "new_reply": "Nova Resposta" }, "media_selection": { @@ -386,8 +405,8 @@ "photo": "foto", "video": "vídeo", "attachment_broken": "Aquest %s està trencat i no pot ser\ncarregat a Mastodon.", - "description_photo": "Descriu la foto per als disminuïts visuals...", - "description_video": "Descriu el vídeo per als disminuïts visuals...", + "description_photo": "Descriu la foto per a les persones amb diversitat funcional...", + "description_video": "Descriu el vídeo per a les persones amb diversitat funcional...", "load_failed": "Ha fallat la càrrega", "upload_failed": "Pujada fallida", "can_not_recognize_this_media_attachment": "No es pot reconèixer aquest adjunt multimèdia", @@ -426,13 +445,13 @@ "custom_emoji_picker": "Selector d'Emoji Personalitzat", "enable_content_warning": "Activa l'Avís de Contingut", "disable_content_warning": "Desactiva l'Avís de Contingut", - "post_visibility_menu": "Menú de Visibilitat de Publicació", - "post_options": "Opcions del tut", + "post_visibility_menu": "Menú de Visibilitat del Tut", + "post_options": "Opcions del Tut", "posting_as": "Publicant com a %s" }, "keyboard": { - "discard_post": "Descarta la Publicació", - "publish_post": "Envia la Publicació", + "discard_post": "Descarta el Tut", + "publish_post": "Envia el Tut", "toggle_poll": "Commuta l'enquesta", "toggle_content_warning": "Commuta l'Avís de Contingut", "append_attachment_entry": "Afegeix Adjunt - %s", @@ -444,11 +463,15 @@ "follows_you": "Et segueix" }, "dashboard": { - "posts": "publicacions", - "following": "seguint", - "followers": "seguidors" + "my_posts": "tuts", + "my_following": "seguint", + "my_followers": "seguidors", + "other_posts": "tuts", + "other_following": "seguint", + "other_followers": "seguidors" }, "fields": { + "joined": "S'hi va unir", "add_row": "Afegeix fila", "placeholder": { "label": "Etiqueta", @@ -460,9 +483,9 @@ } }, "segmented_control": { - "posts": "Publicacions", + "posts": "Tuts", "replies": "Respostes", - "posts_and_replies": "Publicacions i Respostes", + "posts_and_replies": "Tuts i Respostes", "media": "Mèdia", "about": "Quant a" }, @@ -476,12 +499,12 @@ "message": "Confirma deixar de silenciar a %s" }, "confirm_block_user": { - "title": "Bloqueja el Compte", - "message": "Confirma per a bloquejar %s" + "title": "Bloca el Compte", + "message": "Confirma per a blocar %s" }, "confirm_unblock_user": { - "title": "Desbloqueja el Compte", - "message": "Confirma per a desbloquejar %s" + "title": "Desbloca el Compte", + "message": "Confirma per a desblocar %s" }, "confirm_show_reblogs": { "title": "Mostra els Impulsos", @@ -541,7 +564,7 @@ "all": "Tots", "people": "Gent", "hashtags": "Etiquetes", - "posts": "Publicacions" + "posts": "Tuts" }, "empty_state": { "no_results": "No hi ha resultats" @@ -552,13 +575,13 @@ }, "discovery": { "tabs": { - "posts": "Publicacions", + "posts": "Tuts", "hashtags": "Etiquetes", "news": "Notícies", "community": "Comunitat", "for_you": "Per a tu" }, - "intro": "Aquestes son les publicacions que criden l'atenció en el teu racó de Mastodon." + "intro": "Aquests son els tuts que criden l'atenció en el teu racó de Mastodon." }, "favorite": { "title": "Els teus Favorits" @@ -588,8 +611,8 @@ } }, "thread": { - "back_title": "Publicació", - "title": "Publicació de %s" + "back_title": "Tut", + "title": "Tut de %s" }, "settings": { "title": "Configuració", @@ -609,9 +632,9 @@ }, "notifications": { "title": "Notificacions", - "favorites": "Ha afavorit el meu estat", + "favorites": "Ha afavorit el meu tut", "follows": "Em segueix", - "boosts": "Ha impulsat el meu estat", + "boosts": "Ha impulsat el meu tut", "mentions": "M'ha mencionat", "trigger": { "anyone": "algú", @@ -653,7 +676,7 @@ "title": "Informa sobre %s", "step1": "Pas 1 de 2", "step2": "Pas 2 de 2", - "content1": "Hi ha alguna altre publicació que vulguis afegir a l'informe?", + "content1": "Hi ha algun altre tut que vulguis afegir a l'informe?", "content2": "Hi ha alguna cosa que els moderadors hagin de saber sobre aquest informe?", "report_sent_title": "Gràcies per informar, ho investigarem.", "send": "Envia Informe", @@ -662,7 +685,7 @@ "reported": "REPORTAT", "step_one": { "step_1_of_4": "Pas 1 de 4", - "whats_wrong_with_this_post": "Quin és el problema amb aquesta publicació?", + "whats_wrong_with_this_post": "Quin és el problema amb aquest tut?", "whats_wrong_with_this_account": "Quin és el problema amb aquest compte?", "whats_wrong_with_this_username": "Quin és el problema amb %s?", "select_the_best_match": "Selecciona la millor coincidència", @@ -683,7 +706,7 @@ }, "step_three": { "step_3_of_4": "Pas 3 de 4", - "are_there_any_posts_that_back_up_this_report": "Hi ha alguna publicació que recolzi aquest informe?", + "are_there_any_posts_that_back_up_this_report": "Hi ha alguns tuts que recolzin aquest informe?", "select_all_that_apply": "Selecciona tot el que correspongui" }, "step_four": { @@ -692,14 +715,14 @@ }, "step_final": { "dont_want_to_see_this": "No vols veure això?", - "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "Quan veus alguna cosa que no t'agrada a Mastodon, pots eliminar la persona de la vostra experiència.", + "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "Quan veus alguna cosa que no t'agrada a Mastodon, pots eliminar la persona de la teva experiència.", "unfollow": "Deixa de seguir", "unfollowed": "S'ha deixat de seguir", "unfollow_user": "Deixa de seguir %s", "mute_user": "Silencia %s", - "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "No veuràs les seves publicacions o impulsos a la teva línia de temps personal. No sabran que han estat silenciats.", + "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "No veuràs els seus tuts o impulsos a la teva línia de temps personal. No sabran que han estat silenciats.", "block_user": "Bloca %s", - "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "Ja no podran seguir ni veure les teves publicacions, però poden veure si han estat bloquejats.", + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "Ja no podran seguir ni veure els teus tus, però poden veure si han estat blocats.", "while_we_review_this_you_can_take_action_against_user": "Mentre ho revisem, pots prendre mesures contra %s" } }, @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Marcadors" + }, + "followed_tags": { + "title": "Etiquetes seguides", + "header": { + "posts": "tuts", + "participants": "participants", + "posts_today": "tuts d'avui" + }, + "actions": { + "follow": "Segueix", + "unfollow": "Deixa de seguir" + } } } } diff --git a/Localization/StringsConvertor/input/ckb.lproj/app.json b/Localization/StringsConvertor/input/ckb.lproj/app.json index 787bbea36..e7222d645 100644 --- a/Localization/StringsConvertor/input/ckb.lproj/app.json +++ b/Localization/StringsConvertor/input/ckb.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "بیرگە پاک بکەوە", "message": "سەرکەوتووانە بیرگەی %s پاک کرایەوە." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Create account", "see_more": "زیاتر ببینە", "preview": "پێشبینین", + "copy": "Copy", "share": "هاوبەشی بکە", "share_user": "%s هاوبەش بکە", "share_post": "هاوبەشی بکە", @@ -91,12 +97,16 @@ "block_domain": "%s ئاستەنگ بکە", "unblock_domain": "%s ئاستەنگ مەکە", "settings": "رێکخستنەکان", - "delete": "بیسڕەوە" + "delete": "بیسڕەوە", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "ماڵەوە", - "search": "بگەڕێ", - "notification": "ئاگادارکردنەوەکان", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "پرۆفایل" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "ناوەڕۆکی هەستیار", "media_content_warning": "دەستی پیا بنێ بۆ نیشاندانی", "tap_to_reveal": "دەستی پیا بنێ بۆ نیشاندانی", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "دەنگ بدە", "closed": "داخراوە" @@ -153,6 +165,7 @@ "show_image": "وێنەکە نیشان بدە", "show_gif": "گیفەکە نیشان بدە", "show_video_player": "ڤیدیۆکە لێ بدە", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "دەستی پیا بنێ و بیگرە بۆ نیشاندانی پێڕستەکە" }, "tag": { @@ -168,6 +181,12 @@ "private": "تەنیا شوێنکەوتووەکانی دەتوانن ئەم پۆستە ببینن.", "private_from_me": "تەنیا شوێنکەوتووەکانم دەتوانن ئەم پۆستە ببینن.", "direct": "تەنیا بەکارهێنەرە ئاماژە پێکراوەکە دەتوانێت ئەم پۆستە ببینێت." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "پۆستەکان", - "following": "شوێنکەوتن", - "followers": "شوێنکەوتوو" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "ڕیز زیاد بکە", "placeholder": { "label": "ناونیشان", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/cs.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/cs.lproj/Localizable.stringsdict index 6e44e9f0a..63e324a1b 100644 --- a/Localization/StringsConvertor/input/cs.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/cs.lproj/Localizable.stringsdict @@ -65,7 +65,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + %#@character_count@ zbývá character_count NSStringFormatSpecTypeKey diff --git a/Localization/StringsConvertor/input/cs.lproj/app.json b/Localization/StringsConvertor/input/cs.lproj/app.json index 680eb01bb..30d5eb26c 100644 --- a/Localization/StringsConvertor/input/cs.lproj/app.json +++ b/Localization/StringsConvertor/input/cs.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Vyčistit mezipaměť", "message": "Úspěšně vyčištěno %s mezipaměti." + }, + "translation_failed": { + "title": "Poznámka", + "message": "Překlad se nezdařil. Správce možná nepovolil překlad na tomto serveru nebo tento server používá starší verzi Mastodonu, kde překlady ještě nejsou podporovány.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Vytvořit účet", "see_more": "Zobrazit více", "preview": "Náhled", + "copy": "Kopírovat", "share": "Sdílet", "share_user": "Sdílet %s", "share_post": "Sdílet příspěvek", @@ -91,12 +97,16 @@ "block_domain": "Blokovat %s", "unblock_domain": "Odblokovat %s", "settings": "Nastavení", - "delete": "Smazat" + "delete": "Smazat", + "translate_post": { + "title": "Přeložit z %s", + "unknown_language": "Neznámý" + } }, "tabs": { "home": "Domů", - "search": "Hledat", - "notification": "Oznamování", + "search_and_explore": "Hledat a zkoumat", + "notifications": "Oznámení", "profile": "Profil" }, "keyboard": { @@ -113,8 +123,8 @@ "open_author_profile": "Otevřít profil autora", "open_reblogger_profile": "Otevřít rebloggerův profil", "reply_status": "Odpovědět na příspěvek", - "toggle_reblog": "Toggle Reblog on Post", - "toggle_favorite": "Toggle Favorite on Post", + "toggle_reblog": "Přepnout Reblog na příspěvku", + "toggle_favorite": "Přepnout Oblíbené na příspěvku", "toggle_content_warning": "Přepnout varování obsahu", "preview_image": "Náhled obrázku" }, @@ -132,6 +142,8 @@ "sensitive_content": "Citlivý obsah", "media_content_warning": "Klepnutím kdekoli zobrazíte", "tap_to_reveal": "Klepnutím zobrazit", + "load_embed": "Načíst vložené", + "link_via_user": "%s přes %s", "poll": { "vote": "Hlasovat", "closed": "Uzavřeno" @@ -153,6 +165,7 @@ "show_image": "Zobrazit obrázek", "show_gif": "Zobrazit GIF", "show_video_player": "Zobrazit video přehrávač", + "share_link_in_post": "Sdílet odkaz v příspěvku", "tap_then_hold_to_show_menu": "Klepnutím podržte pro zobrazení nabídky" }, "tag": { @@ -168,6 +181,12 @@ "private": "Pouze jejich sledující mohou vidět tento příspěvek.", "private_from_me": "Pouze moji sledující mohou vidět tento příspěvek.", "direct": "Pouze zmíněný uživatel může vidět tento příspěvek." + }, + "translation": { + "translated_from": "Přeloženo z %s pomocí %s", + "unknown_language": "Neznámý", + "unknown_provider": "Neznámý", + "show_original": "Zobrazit originál" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Sleduje vás" }, "dashboard": { - "posts": "příspěvky", - "following": "sledování", - "followers": "sledující" + "my_posts": "příspěvky", + "my_following": "sledování", + "my_followers": "sledující", + "other_posts": "příspěvky", + "other_following": "sledování", + "other_followers": "sledující" }, "fields": { + "joined": "Připojen/a", "add_row": "Přidat řádek", "placeholder": { "label": "Označení", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Záložky" + }, + "followed_tags": { + "title": "Sledované štítky", + "header": { + "posts": "příspěvky", + "participants": "účastníci", + "posts_today": "příspěvky dnes" + }, + "actions": { + "follow": "Sledovat", + "unfollow": "Přestat sledovat" + } } } } diff --git a/Localization/StringsConvertor/input/cy.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/cy.lproj/Localizable.stringsdict index 9e4c09959..33bcd5a8d 100644 --- a/Localization/StringsConvertor/input/cy.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/cy.lproj/Localizable.stringsdict @@ -13,23 +13,23 @@ NSStringFormatValueTypeKey ld zero - %ld unread notification + %ld hysbysiad heb ei ddarllen one - 1 unread notification + %ld hysbysiad heb ei ddarllen two - %ld unread notification + %ld hysbysiad heb eu darllen few - %ld unread notification + %ld hysbysiad heb eu darllen many - %ld unread notification + %ld hysbysiad heb eu darllen other - %ld unread notification + %ld hysbysiad heb eu darllen a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + Mae'r terfyn mewnbwn yn fwy na %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -37,23 +37,23 @@ NSStringFormatValueTypeKey ld zero - %ld characters + %ld nod one - 1 character + %ld nod two - %ld characters + %ld nod few - %ld characters + %ld nod many - %ld characters + %ld nod other - %ld nodau + %ld nod a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + Mae'r terfyn mewnbwn yn %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -61,23 +61,23 @@ NSStringFormatValueTypeKey ld zero - %ld characters + %ld nod one - 1 character + %ld nod two - %ld characters + %ld nod few - %ld characters + %ld nod many - %ld characters + %ld nod other - %ld characters + %ld nod a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + %#@character_count@ ar ôl character_count NSStringFormatSpecTypeKey @@ -85,17 +85,17 @@ NSStringFormatValueTypeKey ld zero - %ld characters + %ld nod one - 1 character + %ld nod two - %ld characters + %ld nod few - %ld characters + %ld nod many - %ld characters + %ld nod other - %ld characters + %ld nod plural.count.followed_by_and_mutual @@ -128,17 +128,17 @@ NSStringFormatValueTypeKey ld zero - Followed by %1$@, and %ld mutuals + Dilynwyd gan %1$@, a %ld mewn cyffredin one - Followed by %1$@, and another mutual + Dilynwyd gan %1$@, a pherson gyffredin two - Followed by %1$@, and %ld mutuals + Dilynwyd gan %1$@, a %ld mewn cyffredin few - Followed by %1$@, and %ld mutuals + Dilynwyd gan %1$@, a %ld mewn cyffredin many - Followed by %1$@, and %ld mutuals + Dilynwyd gan %1$@, a %ld mewn cyffredin other - Followed by %1$@, and %ld mutuals + Dilynwyd gan %1$@, a %ld mewn cyffredin plural.count.metric_formatted.post @@ -152,17 +152,17 @@ NSStringFormatValueTypeKey ld zero - post + tŵt one - post + tŵt two - postiau + tŵt few - posts + tŵt many - posts + tŵt other - postiau + postiadau plural.count.media @@ -176,17 +176,17 @@ NSStringFormatValueTypeKey ld zero - %ld media + %ld cyfrwng one - 1 media + %ld cyfrwng two - %ld media + %ld gyfrwng few - %ld media + %ld cyfrwng many - %ld media + %ld cyfrwng other - %ld media + %ld cyfrwng plural.count.post @@ -200,17 +200,17 @@ NSStringFormatValueTypeKey ld zero - %ld posts + %ld post one - 1 post + %ld post two - %ld posts + %ld bost few - %ld posts + %ld post many - %ld posts + %ld post other - %ld posts + %ld post plural.count.favorite @@ -224,17 +224,17 @@ NSStringFormatValueTypeKey ld zero - %ld favorites + %ld ffefrynnau one - 1 favorite + %ld ffefryn two - %ld favorites + %ld ffefryn few - %ld favorites + %ld ffefryn many - %ld favorites + %ld ffefryn other - %ld favorites + %ld ffefryn plural.count.reblog @@ -248,17 +248,17 @@ NSStringFormatValueTypeKey ld zero - %ld reblogs + %ld ailflogiau one - 1 reblog + %ld ailflog two - %ld reblogs + %ld ailflog few - %ld reblogs + %ld ailflog many - %ld reblogs + %ld ailflog other - %ld reblogs + %ld o ailflogiau plural.count.reply @@ -272,17 +272,17 @@ NSStringFormatValueTypeKey ld zero - %ld replies + %ld ymatebau one - 1 reply + %ld ymateb two - %ld replies + %ld ymateb few - %ld replies + %ld ymateb many - %ld replies + %ld o ymatebau other - %ld replies + %ld ymateb plural.count.vote @@ -296,17 +296,17 @@ NSStringFormatValueTypeKey ld zero - %ld votes + %ld pleidleisiau one - 1 vote + %ld pleidlais two - %ld votes + %ld bleidlais few - %ld votes + %ld phleidlais many - %ld votes + %ld pleidlais other - %ld votes + %ld pleidlais plural.count.voter @@ -320,17 +320,17 @@ NSStringFormatValueTypeKey ld zero - %ld voters + %ld pleidleiswyr one - 1 voter + %ld pleidleisiwr two - %ld voters + %ld bleidleisiwr few - %ld voters + %ld phleidleisiwr many - %ld voters + %ld pleidleisiwr other - %ld voters + %ld pleidleisiwr plural.people_talking @@ -344,17 +344,17 @@ NSStringFormatValueTypeKey ld zero - %ld people talking + %ld person yn trafod one - 1 people talking + %ld person yn trafod two - %ld people talking + %ld berson yn trafod few - %ld people talking + %ld o bobl yn trafod many - %ld people talking + %ld o bobl yn trafod other - %ld people talking + %ld o bobl yn trafod plural.count.following @@ -368,17 +368,17 @@ NSStringFormatValueTypeKey ld zero - %ld following + %ld yn dilyn one - 1 following + %ld yn dilyn two - %ld following + %ld yn dilyn few - %ld following + %ld yn dilyn many - %ld following + %ld yn dilyn other - %ld following + %ld yn dilyn plural.count.follower @@ -392,17 +392,17 @@ NSStringFormatValueTypeKey ld zero - %ld followers + %ld dilynwyr one - 1 follower + %ld dilynwr two - %ld followers + %ld ddilynwr few - %ld followers + %ld dilynwr many - %ld followers + %ld o ddilynwyr other - %ld followers + %ld dilynwr date.year.left @@ -416,17 +416,17 @@ NSStringFormatValueTypeKey ld zero - %ld years left + %ld blwyddyn ar ôl one - 1 year left + %ld blwyddyn ar ôl two - %ld years left + %ld flwyddyn ar ôl few - %ld years left + %ld blwyddyn ar ôl many - %ld years left + %ld blwyddyn ar ôl other - %ld years left + %ld blwyddyn ar ôl date.month.left @@ -440,17 +440,17 @@ NSStringFormatValueTypeKey ld zero - %ld months left + %ld mis ar ôl one - 1 months left + %ld mis ar ôl two - %ld months left + %ld fis ar ôl few - %ld months left + %ld mis ar ôl many - %ld months left + %ld mis ar ôl other - %ld months left + %ld mis ar ôl date.day.left @@ -464,17 +464,17 @@ NSStringFormatValueTypeKey ld zero - %ld days left + %ld diwrnod ar ôl one - 1 day left + %ld diwrnod ar ôl two - %ld days left + %ld ddiwrnod ar ôl few - %ld days left + %ld diwrnod ar ôl many - %ld days left + %ld diwrnod ar ôl other - %ld days left + %ld diwrnod ar ôl date.hour.left @@ -488,17 +488,17 @@ NSStringFormatValueTypeKey ld zero - %ld hours left + %ld awr ar ôl one - 1 hour left + %ld awr ar ôl two - %ld hours left + %ld awr ar ôl few - %ld hours left + %ld awr ar ôl many - %ld hours left + %ld awr ar ôl other - %ld hours left + %ld awr ar ôl date.minute.left @@ -512,17 +512,17 @@ NSStringFormatValueTypeKey ld zero - %ld minutes left + %ld munud ar ôl one - 1 minute left + %ld munud ar ôl two - %ld minutes left + %ld funud ar ôl few - %ld minutes left + %ld munud ar ôl many - %ld minutes left + %ld munud ar ôl other - %ld minutes left + %ld munud ar ôl date.second.left @@ -536,17 +536,17 @@ NSStringFormatValueTypeKey ld zero - %ld seconds left + %ld eiliad ar ôl one - 1 second left + %ld eiliad ar ôl two - %ld seconds left + %ld eiliad ar ôl few - %ld seconds left + %ld eiliad ar ôl many - %ld seconds left + %ld eiliad ar ôl other - %ld seconds left + %ld eiliad ar ôl date.year.ago.abbr @@ -560,17 +560,17 @@ NSStringFormatValueTypeKey ld zero - %ldy ago + %ld blwyddyn yn ôl one - 1y ago + %ld blwyddyn yn ôl two - %ldy ago + %ld flwyddyn yn ôl few - %ldy ago + %ld blwyddyn yn ôl many - %ldy ago + %ld blwyddyn yn ôl other - %ldy ago + %ld blwyddyn yn ôl date.month.ago.abbr @@ -584,17 +584,17 @@ NSStringFormatValueTypeKey ld zero - %ldM ago + %ld munud yn ôl one - 1M ago + %ld munud yn ôl two - %ldM ago + %ld funud yn ôl few - %ldM ago + %ld munud yn ôl many - %ldM ago + %ld munud yn ôl other - %ldM ago + %ld munud yn ôl date.day.ago.abbr @@ -608,17 +608,17 @@ NSStringFormatValueTypeKey ld zero - %ldd ago + %ldd yn ôl one - 1d ago + %ldd yn ôl two - %ldd ago + %ldd yn ôl few - %ldd ago + %ldd yn ôl many - %ldd ago + %ldd yn ôl other - %ldd ago + %ldd yn ôl date.hour.ago.abbr @@ -632,17 +632,17 @@ NSStringFormatValueTypeKey ld zero - %ldh ago + %ld awr yn ôl one - 1h ago + %ld awr yn ôl two - %ldh ago + %ld awr yn ôl few - %ldh ago + %ld awr yn ôl many - %ldh ago + %ld awr yn ôl other - %ldh ago + %ld awr yn ôl date.minute.ago.abbr @@ -656,17 +656,17 @@ NSStringFormatValueTypeKey ld zero - %ldm ago + %ld munud yn ôl one - 1m ago + %ld munud yn ôl two - %ldm ago + %ld funud yn ôl few - %ldm ago + %ld munud yn ôl many - %ldm ago + %ld munud yn ôl other - %ldm ago + %ld munud yn ôl date.second.ago.abbr @@ -680,17 +680,17 @@ NSStringFormatValueTypeKey ld zero - %lds ago + %ld eiliad yn ôl one - 1s ago + %ld eiliad yn ôl two - %lds ago + %ld eiliad yn ôl few - %lds ago + %ld eiliad yn ôl many - %lds ago + %ld eiliad yn ôl other - %lds ago + %ld eiliad yn ôl diff --git a/Localization/StringsConvertor/input/cy.lproj/app.json b/Localization/StringsConvertor/input/cy.lproj/app.json index fec3197be..b276dfa4b 100644 --- a/Localization/StringsConvertor/input/cy.lproj/app.json +++ b/Localization/StringsConvertor/input/cy.lproj/app.json @@ -2,726 +2,761 @@ "common": { "alerts": { "common": { - "please_try_again": "Please try again.", - "please_try_again_later": "Please try again later." + "please_try_again": "Ceisiwch eto.", + "please_try_again_later": "Ceisiwch eto nes ymlaen." }, "sign_up_failure": { - "title": "Sign Up Failure" + "title": "Gwall Ymgofrestru" }, "server_error": { - "title": "Server Error" + "title": "Gwall Gweinydd" }, "vote_failure": { - "title": "Vote Failure", - "poll_ended": "The poll has ended" + "title": "Gwall Pleidleisio", + "poll_ended": "Mae'r pôl wedi dod i ben" }, "discard_post_content": { - "title": "Discard Draft", - "message": "Confirm to discard composed post content." + "title": "Dileu Drafft", + "message": "Cadarnhau i ddileu post drafft." }, "publish_post_failure": { - "title": "Publish Failure", - "message": "Failed to publish the post.\nPlease check your internet connection.", + "title": "Gwall Cyhoeddi", + "message": "Gwall wrth gyhoeddi'r tŵt.\nGwiriwch eich cysylltiad i'r rhyngrhwyd.", "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": "Ni ellir ychwanegu fideo at bost sy'n cynnwys lluniau yn barod.", + "more_than_one_video": "Ni ellir ychwanegu mwy nag un fideo." } }, "edit_profile_failure": { - "title": "Edit Profile Error", - "message": "Cannot edit profile. Please try again." + "title": "Gwall Golygu Proffil", + "message": "Ni ellir golygu proffil. Ceisiwch eto." }, "sign_out": { - "title": "Sign Out", - "message": "Are you sure you want to sign out?", - "confirm": "Sign Out" + "title": "Allgofnodi", + "message": "Ydych chi wir eisiau allgofnodi?", + "confirm": "Allgofnodi" }, "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": "Ydych chi wir, wir eisiau blocio'r holl %s? Fel arfer, mae blocio neu anwybyddu pobl penodol yn broses mwy effeithiol. Ni fyddwch yn gweld cynnwys o'r parth hwnnw a bydd eich dilynwyr o'r parth hwnnw yn cael eu ddileu.", + "block_entire_domain": "Blocio parth" }, "save_photo_failure": { - "title": "Save Photo Failure", - "message": "Please enable the photo library access permission to save the photo." + "title": "Gwall Cadw Llun", + "message": "Rhowch caniatád mynediad i'r Photo Library i gadw'r llun." }, "delete_post": { - "title": "Delete Post", - "message": "Are you sure you want to delete this post?" + "title": "Dileu Tŵt", + "message": "Ydych chi wir eisiau dileu'r post hwn?" }, "clean_cache": { - "title": "Clean Cache", - "message": "Successfully cleaned %s cache." + "title": "Clirio storfa", + "message": "Cliriwyd storfa %s yn llwyddiannus." + }, + "translation_failed": { + "title": "Nodyn", + "message": "Methwyd cyfieithu. Efallai nad yw'r gweinyddwr wedi galluogi cyfieithiadau ar y gweinydd hwn neu mae'r gweinydd hwn yn rhedeg fersiwn hŷn o Mastodon lle nad yw cyfieithiadau ar gael eto.", + "button": "Iawn" } }, "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": "Log in", - "sign_up": "Create account", - "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" + "back": "Nôl", + "next": "Ymlaen", + "previous": "Blaenorol", + "open": "Agor", + "add": "Ychwanegu", + "remove": "Dileu", + "edit": "Golygu", + "save": "Cadw", + "ok": "Iawn", + "done": "Iawn", + "confirm": "Cadarnhau", + "continue": "Parhau", + "compose": "Creu", + "cancel": "Canslo", + "discard": "Diddymu", + "try_again": "Ceisio eto", + "take_photo": "Tynnu Llun", + "save_photo": "Cadw Llun", + "copy_photo": "Copïo Llun", + "sign_in": "Mewngofnodi", + "sign_up": "Creu cyfrif", + "see_more": "Gweld Mwy", + "preview": "Rhagolwg", + "copy": "Copïo", + "share": "Rhannu", + "share_user": "Rhannu %s", + "share_post": "Rhannu Tŵt", + "open_in_safari": "Agor yn Safari", + "open_in_browser": "Agor yn y Porwr", + "find_people": "Dilyn pobl newydd", + "manually_search": "Chwilio yn fanwl", + "skip": "Anwybyddu", + "reply": "Ymateb", + "report_user": "Riportio %s", + "block_domain": "Blocio %s", + "unblock_domain": "Dadflocio %s", + "settings": "Gosodiadau", + "delete": "Dileu", + "translate_post": { + "title": "Cyfieithu o %s", + "unknown_language": "Anhysbys" + } }, "tabs": { - "home": "Home", - "search": "Search", - "notification": "Notification", - "profile": "Profile" + "home": "Hafan", + "search_and_explore": "Chwilio ac Archwilio", + "notifications": "Hysbysiadau", + "profile": "Proffil" }, "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": "Newid i %s", + "compose_new_post": "Creu Tŵt Newydd", + "show_favorites": "Dangos Ffefrynnau", + "open_settings": "Agor Gosodiadau" }, "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 Blaenorol", + "next_status": "Tŵt Nesaf", + "open_status": "Agor Tŵt", + "open_author_profile": "Agor Proffil yr Awdur", + "open_reblogger_profile": "Agor Proffil yr Ailflogwr", + "reply_status": "Ymateb i Tŵt", + "toggle_reblog": "Toglo Ailfloggio ar Tŵt", + "toggle_favorite": "Toglo Ffefrynnu ar Tŵt", + "toggle_content_warning": "Toglo Rhybudd Cynnwys", + "preview_image": "Rhagolygu'r Llun" }, "segmented_control": { - "previous_section": "Previous Section", - "next_section": "Next Section" + "previous_section": "Adran Flaenorol", + "next_section": "Adran Nesaf" } }, "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", - "sensitive_content": "Sensitive Content", - "media_content_warning": "Tap anywhere to reveal", - "tap_to_reveal": "Tap to reveal", + "user_reblogged": "%s wedi ailflogio", + "user_replied_to": "Wedi ymateb i %s", + "show_post": "Dangos Tŵt", + "show_user_profile": "Dangos proffil y defnyddiwr", + "content_warning": "Rhybudd Cynnwys", + "sensitive_content": "Cynnwys Sensitif", + "media_content_warning": "Tapiwch unrhywle i weld", + "tap_to_reveal": "Tapiwch i weld", + "load_embed": "Llwytho Planiad", + "link_via_user": "%s trwy %s", "poll": { - "vote": "Vote", - "closed": "Closed" + "vote": "Pleidleisio", + "closed": "Wedi cau" }, "meta_entity": { - "url": "Link: %s", - "hashtag": "Hashtag: %s", - "mention": "Show Profile: %s", - "email": "Email address: %s" + "url": "Dolen: %s", + "hashtag": "Hashnod: %s", + "mention": "Dangos Proffil: %s", + "email": "Cyfeiriad e-bost: %s" }, "actions": { - "reply": "Reply", + "reply": "Ymateb", "reblog": "Hybwch", - "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" + "unreblog": "Dadwneud ailfloggiad", + "favorite": "Ffefrynnu", + "unfavorite": "Dad-ffefrynnu", + "menu": "Dewislen", + "hide": "Cuddio", + "show_image": "Dangos llun", + "show_gif": "Dangos GIF", + "show_video_player": "Dangos chwaraewr fideo", + "share_link_in_post": "Rhannu'r Ddolen yn y Postiad", + "tap_then_hold_to_show_menu": "Tapiwch a gwasgu i gael y ddewislen" }, "tag": { "url": "URL", - "mention": "Mention", - "link": "Link", - "hashtag": "Hashtag", - "email": "Email", + "mention": "Sôn", + "link": "Dolen", + "hashtag": "Hashnod", + "email": "E-bost", "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": "Gall pawb weld y post hwn ond nid yn y ffrwd cyhoeddus.", + "private": "Dim ond eu dilynwyr nhw sy'n gallu gweld y post hwn.", + "private_from_me": "Dim ond fy nilynwyr ni sy'n gallu gweld y post hwn.", + "direct": "Dim ond y ddefnyddiwr â soniwyd sy'n gallu gweld y post hwn." + }, + "translation": { + "translated_from": "Cyfieithwyd o %s gan ddefnyddio %s", + "unknown_language": "Anhysbys", + "unknown_provider": "Anhysbys", + "show_original": "Dangos y Gwreiddiol" } }, "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", - "show_reblogs": "Show Reblogs", - "hide_reblogs": "Hide Reblogs" + "follow": "Dilyn", + "following": "Yn dilyn", + "request": "Gwneud cais", + "pending": "Yn aros", + "block": "Blocio", + "block_user": "Blocio %s", + "block_domain": "Blocio %s", + "unblock": "Dadflocio", + "unblock_user": "Dadflocio %s", + "blocked": "Wedi blocio", + "mute": "Anwybyddu", + "mute_user": "Anwybyddu %s", + "unmute": "Dad-anwybyddu", + "unmute_user": "Dad-anwybyddu %s", + "muted": "Wedi anwybyddu", + "edit_info": "Golygu", + "show_reblogs": "Dangos Ailfloggiau", + "hide_reblogs": "Cuddio Ailfloggiau" }, "timeline": { - "filtered": "Filtered", + "filtered": "Wedi'i hidlo", "timestamp": { - "now": "Now" + "now": "Nawr" }, "loader": { - "load_missing_posts": "Load missing posts", - "loading_missing_posts": "Loading missing posts...", - "show_more_replies": "Show more replies" + "load_missing_posts": "Llwytho postau coll", + "loading_missing_posts": "Wrthi'n llwytho postau coll...", + "show_more_replies": "Dangos mwy o ymatebion" }, "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": "Ni Chanfuwyd Post", + "blocking_warning": "Ni allwch gweld proffil y ddefnyddiwr hwn\nos ydych wedi'u blocio.\nMae'ch proffil chi yn edrych fel hyn iddynt.", + "user_blocking_warning": "Ni allwch gweld proffil %s\nos ydych wedi'u blocio.\nMae'ch proffil chi yn edrych fel hyn iddynt.", + "blocked_warning": "Ni allwch gweld proffil y ddefnyddiwr hwn\ngan eu bod wedi eich blocio chi.", + "user_blocked_warning": "Ni allwch gweld proffil %s\ngan eu bod wedi eich blocio chi.", + "suspended_warning": "Mae'r defnyddiwr hwn wedi derbyn gwaharddiad.", + "user_suspended_warning": "Mae cyfrif %s wedi derbyn gwaharddiad." } } } }, "scene": { "welcome": { - "slogan": "Social networking\nback in your hands.", - "get_started": "Get Started", - "log_in": "Log In" + "slogan": "Rhwydweithio cymdeithasol, \nyn eich dwylo chi.", + "get_started": "Cychwyn Arni", + "log_in": "Mewngofnodi" }, "login": { - "title": "Welcome back", - "subtitle": "Log you in on the server you created your account on.", + "title": "Croeso nôl", + "subtitle": "Mewngofnodi ar y gweinydd y rydych chi wedi creu cyfrif arno.", "server_search_field": { - "placeholder": "Enter URL or search for your server" + "placeholder": "Mewnosod URL neu chwilio am eich gweinydd" } }, "server_picker": { - "title": "Mastodon is made of users in different servers.", - "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.", + "title": "Mae Mastodon yn cynnwys defnyddwyr o weinyddion gwahanol.", + "subtitle": "Dewiswch gweinydd yn ôl eich lleoliad, diddordebau, neu defnydd cyffredin. Gallwch siarad gydag unrhywun ar Mastodon, yn annibynnol o weinyddion chi.", "button": { "category": { - "all": "All", - "all_accessiblity_description": "Category: All", - "academia": "academia", - "activism": "activism", - "food": "food", + "all": "Popeth", + "all_accessiblity_description": "Categori: Popeth", + "academia": "academaidd", + "activism": "gweithgarwch", + "food": "bwyd", "furry": "furry", - "games": "games", - "general": "general", - "journalism": "journalism", - "lgbt": "lgbt", - "regional": "regional", - "art": "art", - "music": "music", - "tech": "tech" + "games": "gemau", + "general": "cyffredinol", + "journalism": "newyddiaduraeth", + "lgbt": "LHDT+", + "regional": "rhanbarthol", + "art": "celf", + "music": "cerddoriaeth", + "tech": "technoleg" }, - "see_less": "See Less", - "see_more": "See More" + "see_less": "Gweld Llai", + "see_more": "Gweld Mwy" }, "label": { - "language": "LANGUAGE", - "users": "USERS", - "category": "CATEGORY" + "language": "IAITH", + "users": "DEFNYDDWYR", + "category": "CATEGORI" }, "input": { - "search_servers_or_enter_url": "Search communities or enter URL" + "search_servers_or_enter_url": "Chwilio cymunedau neu fewnosod URL" }, "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": "Wrthi'n chwilio am weinyddion sydd ar gael...", + "bad_network": "Digwyddodd gwall wrth lwytho'r data. Gwiriwch eich cyswllt â'r rhyngrwyd.", + "no_results": "Dim canlyniadau" } }, "register": { - "title": "Let’s get you set up on %s", - "lets_get_you_set_up_on_domain": "Let’s get you set up on %s", + "title": "Rhoi popeth yn ei le ar %s", + "lets_get_you_set_up_on_domain": "Rhoi popeth yn ei le ar %s", "input": { "avatar": { - "delete": "Delete" + "delete": "Dileu" }, "username": { - "placeholder": "username", - "duplicate_prompt": "This username is taken." + "placeholder": "enw defnyddiwr", + "duplicate_prompt": "Defnyddir yr enw hwn yn barod." }, "display_name": { - "placeholder": "display name" + "placeholder": "enw arddangos" }, "email": { - "placeholder": "email" + "placeholder": "e-bost" }, "password": { - "placeholder": "password", - "require": "Your password needs at least:", - "character_limit": "8 characters", + "placeholder": "cyfrinair", + "require": "Mae angen i'ch cyfrinair gael o leiaf:", + "character_limit": "8 nod", "accessibility": { - "checked": "checked", - "unchecked": "unchecked" + "checked": "ticiwyd", + "unchecked": "na thiciwyd" }, - "hint": "Your password needs at least eight characters" + "hint": "Mae angen o leiaf wyth nod yn eich cyfrinair" }, "invite": { - "registration_user_invite_request": "Why do you want to join?" + "registration_user_invite_request": "Pam ydych chi eisiau ymuno?" } }, "error": { "item": { - "username": "Username", - "email": "Email", - "password": "Password", - "agreement": "Agreement", - "locale": "Locale", - "reason": "Reason" + "username": "Enw defnyddiwr", + "email": "E-bost", + "password": "Cyfrinair", + "agreement": "Cytundeb", + "locale": "Lleoliad", + "reason": "Rheswm" }, "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": "Mae %s yn defnyddio darparwr e-bost nad yw'n cael ei ganiatáu", + "unreachable": "Nid yw %s yn bodoli", + "taken": "Defnyddir %s yn barod", + "reserved": "Mae %s yn air allweddol a chadwyd", + "accepted": "Mae angen cytuno â %s", + "blank": "Mae angen cael %s", + "invalid": "Mae %s yn annilys", + "too_long": "Mae %s yn rhy hir", + "too_short": "Mae %s yn rhy fyr", + "inclusion": "Nid yw %s yn gwerth a chefnogir" }, "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": "Dylai enwau ddefnyddiwr gynnwys nodau alffaniwmerig a thanlinellau yn unig", + "username_too_long": "Enw defnyddiwr yn rhy hir (na all fod yn fwy na 30 nodyn)", + "email_invalid": "Nid yw'n cyfeiriad e-bost dilys", + "password_too_short": "Cyfrinair yn rhy fyr (Rhaid fod o leiaf 8 nodyn)" } } }, "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": "Rhai rheolau sylfaenol.", + "subtitle": "Mae'r rhain yn cael eu gosod a'u gorfodi gan gymedrolwyr %s.", + "prompt": "Wrth barhau, rydych yn cytuno â'r Telerau Gwasanaeth a Pholisi Preifatrwydd %s.", + "terms_of_service": "telerau gwasanaeth", + "privacy_policy": "polisi preifatrwydd", "button": { - "confirm": "I Agree" + "confirm": "Rwy'n cytuno" } }, "confirm_email": { - "title": "One last thing.", - "subtitle": "Tap the link we emailed to you to verify your account.", - "tap_the_link_we_emailed_to_you_to_verify_your_account": "Tap the link we emailed to you to verify your account", + "title": "Un peth olaf.", + "subtitle": "Tapiwch ar y ddolen yn eich e-bost i ddilysu eich cyfrif.", + "tap_the_link_we_emailed_to_you_to_verify_your_account": "Tapiwch ar y ddolen yn eich e-bost i ddilysu eich cyfrif", "button": { - "open_email_app": "Open Email App", - "resend": "Resend" + "open_email_app": "Agor ap e-byst", + "resend": "Ailanfon" }, "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": "Gwiriwch eich e-byst", + "description": "Gwiriwch a yw eich cyfeiriad e-bost yn gywir a hefyd eich ffolder 'junk' os nad ydych wedi ei gwneud.", + "resend_email": "Ailanfon E-bost" }, "open_email_app": { - "title": "Check your inbox.", - "description": "We just sent you an email. Check your junk folder if you haven’t.", + "title": "Gwiriwch eich blwch derbyn.", + "description": "Rydym newydd anfon e-bost atoch chi. Gwiriwch eich ffolder 'junk' os nad ydych wedi ei gwneud.", "mail": "Mail", - "open_email_client": "Open Email Client" + "open_email_client": "Agor Cleient E-byst" } }, "home_timeline": { - "title": "Home", + "title": "Hafan", "navigation_bar_state": { - "offline": "Offline", - "new_posts": "See new posts", - "published": "Published!", - "Publishing": "Publishing post...", + "offline": "All-lein", + "new_posts": "Gweld tŵts newydd", + "published": "Wedi cyhoeddi!", + "Publishing": "Wrthi'n cyhoeddi...", "accessibility": { - "logo_label": "Logo Button", - "logo_hint": "Tap to scroll to top and tap again to previous location" + "logo_label": "Botwm Logo", + "logo_hint": "Tapiwch i sgrolio i'r frig, a thapiwch eto er mwyn mynd i'r lleoliad blaenorol" } } }, "suggestion_account": { - "title": "Find People to Follow", - "follow_explain": "When you follow someone, you’ll see their posts in your home feed." + "title": "Chwilio a Dilyn Pobl", + "follow_explain": "Ar ôl ichi ddilyn rhywun, byddwch yn gweld eu postiadau yn eich ffrwd hafan." }, "compose": { "title": { - "new_post": "New Post", - "new_reply": "New Reply" + "new_post": "Tŵt Newydd", + "new_reply": "Ymateb Newydd" }, "media_selection": { - "camera": "Take Photo", + "camera": "Tynnu Llun", "photo_library": "Photo Library", - "browse": "Browse" + "browse": "Pori" }, - "content_input_placeholder": "Type or paste what’s on your mind", - "compose_action": "Publish", - "replying_to_user": "replying to %s", + "content_input_placeholder": "Teipiwch neu gludo'r hyn sydd ar eich meddwl", + "compose_action": "Cyhoeddi", + "replying_to_user": "yn ymateb i %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...", - "load_failed": "Load Failed", - "upload_failed": "Upload Failed", - "can_not_recognize_this_media_attachment": "Can not recognize this media attachment", - "attachment_too_large": "Attachment too large", - "compressing_state": "Compressing...", - "server_processing_state": "Server Processing..." + "photo": "llun", + "video": "fideo", + "attachment_broken": "Mae %s wedi torri a ni ellir\nuwchlwytho hwn i Mastodon.", + "description_photo": "Disgrifio i'r rheini â nam ar eu golwg...", + "description_video": "Disgrifio i'r rheini â nam ar eu golwg...", + "load_failed": "Methwyd Llwytho", + "upload_failed": "Methwyd Uwchlwytho", + "can_not_recognize_this_media_attachment": "Ni ellir dilysu'r atodiad cyfrwng", + "attachment_too_large": "Mae'r atodiad yn rhy fawr", + "compressing_state": "Wrthi'n cywasgu...", + "server_processing_state": "Mae'r gweinydd yn prosesu..." }, "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", - "the_poll_is_invalid": "The poll is invalid", - "the_poll_has_empty_option": "The poll has empty option" + "duration_time": "Hyd: %s", + "thirty_minutes": "30 munud", + "one_hour": "1 awr", + "six_hours": "6 awr", + "one_day": "1 diwrnod", + "three_days": "3 diwrnod", + "seven_days": "7 diwrnod", + "option_number": "Opsiwn %ld", + "the_poll_is_invalid": "Nid yw'r pôl yn ddilys", + "the_poll_has_empty_option": "Mae gan y pôl opsiwn gwag" }, "content_warning": { - "placeholder": "Write an accurate warning here..." + "placeholder": "Ysgrifenwch rybudd manwl yma..." }, "visibility": { - "public": "Public", - "unlisted": "Unlisted", - "private": "Followers only", - "direct": "Only people I mention" + "public": "Cyhoeddus", + "unlisted": "Heb ei rhestru", + "private": "Dilynwyr yn unig", + "direct": "Dim ond pobl rwy'n eu crybwyll" }, "auto_complete": { - "space_to_add": "Space to add" + "space_to_add": "Lle i ychwanegu" }, "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", - "post_options": "Post Options", - "posting_as": "Posting as %s" + "append_attachment": "Ychwanegu Atodiad", + "append_poll": "Ychwanegu Pôl", + "remove_poll": "Dileu Pôl", + "custom_emoji_picker": "Dewislen Emoji Bersonol", + "enable_content_warning": "Galluogi Rhybudd Cynnwys", + "disable_content_warning": "Analluogi Rhybudd Cynnwys", + "post_visibility_menu": "Dewislen Breifatrwydd Post", + "post_options": "Opsiynau Tŵt", + "posting_as": "Cyhoeddi fel %s" }, "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": "Dileu Tŵt", + "publish_post": "Cyhoeddi Tŵt", + "toggle_poll": "Toglo Pôl", + "toggle_content_warning": "Toglo Rhybudd Cynnwys", + "append_attachment_entry": "Ychwanegu Atodiad - %s", + "select_visibility_entry": "Dewis Preifatrwydd - %s" } }, "profile": { "header": { - "follows_you": "Follows You" + "follows_you": "Yn eich dilyn" }, "dashboard": { - "posts": "postiadau", - "following": "following", - "followers": "followers" + "my_posts": "postiadu", + "my_following": "yn dilyn", + "my_followers": "dilynwyr", + "other_posts": "postiadu", + "other_following": "yn dilyn", + "other_followers": "dilynwyr" }, "fields": { - "add_row": "Add Row", + "joined": "Ymunwyd", + "add_row": "Ychwanegu Rhes", "placeholder": { "label": "Label", - "content": "Content" + "content": "Cynnwys" }, "verified": { - "short": "Verified on %s", - "long": "Ownership of this link was checked on %s" + "short": "Wedi dilysu ar %s", + "long": "Gwiriwyd perchnogaeth y ddolen yma ar %s" } }, "segmented_control": { "posts": "Postiadau", - "replies": "Replies", + "replies": "Ymatebion", "posts_and_replies": "Postiadau ac Atebion", - "media": "Media", - "about": "About" + "media": "Cyfryngau", + "about": "Ynghylch" }, "relationship_action_alert": { "confirm_mute_user": { - "title": "Mute Account", - "message": "Confirm to mute %s" + "title": "Anwybyddu Cyfrif", + "message": "Parhau i anwybyddu %s" }, "confirm_unmute_user": { - "title": "Unmute Account", - "message": "Confirm to unmute %s" + "title": "Dad-anwybyddu Cyfrif", + "message": "Parhau i ddad-anwybyddu %s" }, "confirm_block_user": { - "title": "Block Account", - "message": "Confirm to block %s" + "title": "Blocio Cyfrif", + "message": "Cadarnhau i flocio %s" }, "confirm_unblock_user": { - "title": "Unblock Account", - "message": "Confirm to unblock %s" + "title": "Dadflocio Cyfrif", + "message": "Parhau i ddadflocio %s" }, "confirm_show_reblogs": { - "title": "Show Reblogs", - "message": "Confirm to show reblogs" + "title": "Dangos Ailfloggiau", + "message": "Cadarnhau i ddangos hybiau" }, "confirm_hide_reblogs": { - "title": "Hide Reblogs", - "message": "Confirm to hide reblogs" + "title": "Cuddio Ailflogiau", + "message": "Cadarnhau i guddio ailflogiau" } }, "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": "Dangos afatar", + "edit_avatar_image": "Golygu afatar", + "show_banner_image": "Dangos baner", + "double_tap_to_open_the_list": "Tapiwch dwywaith i agor y restr" } }, "follower": { - "title": "follower", - "footer": "Followers from other servers are not displayed." + "title": "dilynwr", + "footer": "Ni ddangosir dilynwyr o weinyddion eraill." }, "following": { - "title": "following", - "footer": "Follows from other servers are not displayed." + "title": "yn dilyn", + "footer": "Ni ddangosir dilynion o weinyddion eraill." }, "familiarFollowers": { - "title": "Followers you familiar", - "followed_by_names": "Followed by %s" + "title": "Dilynwyr sy'n gyfarwydd ichi", + "followed_by_names": "Dilynwyd gan %s" }, "favorited_by": { - "title": "Favorited By" + "title": "Ffefrynnwyd gan" }, "reblogged_by": { - "title": "Reblogged By" + "title": "Wedi'i hybu gan" }, "search": { - "title": "Search", + "title": "Chwilio", "search_bar": { - "placeholder": "Search hashtags and users", - "cancel": "Cancel" + "placeholder": "Chwilio hashnodau a defnyddwyr", + "cancel": "Canslo" }, "recommend": { - "button_text": "See All", + "button_text": "Gweld Popeth", "hash_tag": { - "title": "Trending on Mastodon", - "description": "Hashtags that are getting quite a bit of attention", - "people_talking": "%s people are talking" + "title": "Pynciau Llosg ar Mastodon", + "description": "Dyma'r hashnodau sy'n derbyn tipyn o sylw", + "people_talking": "%s person yn trafod" }, "accounts": { - "title": "Accounts you might like", - "description": "You may like to follow these accounts", - "follow": "Follow" + "title": "Cyfrifon ar eich cyfer", + "description": "Cyfrifon sydd efallai o ddiddordeb ichi", + "follow": "Dilyn" } }, "searching": { "segment": { - "all": "All", - "people": "People", - "hashtags": "Hashtags", + "all": "Popeth", + "people": "Pobl", + "hashtags": "Hashnodau", "posts": "Postiadau" }, "empty_state": { - "no_results": "No results" + "no_results": "Dim canlyniadau" }, - "recent_search": "Recent searches", - "clear": "Clear" + "recent_search": "Chwiliadau diweddar", + "clear": "Clirio" } }, "discovery": { "tabs": { "posts": "Postiadau", - "hashtags": "Hashtags", - "news": "News", - "community": "Community", - "for_you": "For You" + "hashtags": "Hashnodau", + "news": "Newyddion", + "community": "Cymuned", + "for_you": "I Ti" }, - "intro": "These are the posts gaining traction in your corner of Mastodon." + "intro": "Dyma'r postiadau sy'n denu tipyn o sylw yn eich cŵr Mastodon." }, "favorite": { - "title": "Your Favorites" + "title": "Eich Ffefrynnau" }, "notification": { "title": { - "Everything": "Everything", - "Mentions": "Mentions" + "Everything": "Popeth", + "Mentions": "Crybwylliadau" }, "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": "wedi eich dilyn", + "favorited_your_post": "wedi ffefrynnu eich tŵt", + "reblogged_your_post": "wedi ailfloggio'ch tŵt", + "mentioned_you": "wedi sôn amdanoch", + "request_to_follow_you": "wedi gwneud cais i'ch dilyn", + "poll_has_ended": "pôl wedi dod i ben" }, "keyobard": { - "show_everything": "Show Everything", - "show_mentions": "Show Mentions" + "show_everything": "Dangos Popeth", + "show_mentions": "Dangos Crybwylliadau" }, "follow_request": { - "accept": "Accept", - "accepted": "Accepted", - "reject": "reject", - "rejected": "Rejected" + "accept": "Derbyn", + "accepted": "Wedi Derbyn", + "reject": "gwrthod", + "rejected": "Gwrthodwyd" } }, "thread": { "back_title": "Post", - "title": "Post from %s" + "title": "Tŵt gan %s" }, "settings": { - "title": "Settings", + "title": "Gosodiadau", "section": { "appearance": { - "title": "Appearance", - "automatic": "Automatic", - "light": "Always Light", - "dark": "Always Dark" + "title": "Gwedd", + "automatic": "Awtomatig", + "light": "Golau", + "dark": "Tywyll" }, "look_and_feel": { - "title": "Look and Feel", - "use_system": "Use System", - "really_dark": "Really Dark", - "sorta_dark": "Sorta Dark", - "light": "Light" + "title": "Gwedd", + "use_system": "Dull y System", + "really_dark": "Tywyll Iawn", + "sorta_dark": "Eitha' Tywyll", + "light": "Golau" }, "notifications": { - "title": "Notifications", - "favorites": "Favorites my post", - "follows": "Follows me", - "boosts": "Reblogs my post", - "mentions": "Mentions me", + "title": "Hysbysiadau", + "favorites": "Yn ffefrynnu fy mhost", + "follows": "Yn fy nilyn", + "boosts": "Yn hybu fy mhost", + "mentions": "Yn sôn amdana i", "trigger": { - "anyone": "anyone", - "follower": "a follower", - "follow": "anyone I follow", - "noone": "no one", - "title": "Notify me when" + "anyone": "unrhyw un", + "follower": "dilynwr", + "follow": "unrhyw un o'm dilynion", + "noone": "neb", + "title": "Rhowch wybod i mi pan" } }, "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": "Dewisiadau", + "true_black_dark_mode": "Gwedd tywyll go iawn", + "disable_avatar_animation": "Analluogi rhithffurfiau wedi'u hanimeiddio", + "disable_emoji_animation": "Analluogi emoji wedi'u hanimeiddio", + "using_default_browser": "Defnyddio porwr rhagosodedig i agor dolenni", + "open_links_in_mastodon": "Agor dolenni ym Mastodon" }, "boring_zone": { - "title": "The Boring Zone", - "account_settings": "Account Settings", - "terms": "Terms of Service", - "privacy": "Privacy Policy" + "title": "Yr Ardal Ddiflas", + "account_settings": "Gosodiadau Cyfrif", + "terms": "Telerau Gwasanaeth", + "privacy": "Polisi Preifatrwydd" }, "spicy_zone": { - "title": "The Spicy Zone", - "clear": "Clear Media Cache", - "signout": "Sign Out" + "title": "Yr Ardal Sbeislyd", + "clear": "Clirio Storfa Cyfryngau", + "signout": "Allgofnodi" } }, "footer": { - "mastodon_description": "Mastodon is open source software. You can report issues on GitHub at %s (%s)" + "mastodon_description": "Mae Mastodon yn feddalwedd cod agored. Gallech roi gwybod am wallau ar GitHub: %s (%s)" }, "keyboard": { - "close_settings_window": "Close Settings Window" + "close_settings_window": "Cau Ffenest Gosodiadau" } }, "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": "Riportio", + "title": "Riportio %s", + "step1": "Cam 1 o 2", + "step2": "Cam 2 o 2", + "content1": "Hoffech chi ychwanegu unrhyw postiadau eraill i'r adroddiad?", + "content2": "Oes unrhyw beth y dylai'r cymedrolwyr wybod yn yr adroddiad hwn?", + "report_sent_title": "Diolch am adrodd, byddwn yn ymchwilio i hyn.", + "send": "Anfon adroddiad", + "skip_to_send": "Anfon heb sylw", + "text_placeholder": "Teipiwch neu gludwch sylwadau ychwanegol", + "reported": "WEDI RIPORTIO", "step_one": { - "step_1_of_4": "Step 1 of 4", - "whats_wrong_with_this_post": "What's wrong with this post?", - "whats_wrong_with_this_account": "What's wrong with this account?", - "whats_wrong_with_this_username": "What's wrong with %s?", - "select_the_best_match": "Select the best match", - "i_dont_like_it": "I don’t like it", - "it_is_not_something_you_want_to_see": "It is not something you want to see", - "its_spam": "It’s spam", - "malicious_links_fake_engagement_or_repetetive_replies": "Malicious links, fake engagement, or repetetive replies", - "it_violates_server_rules": "It violates server rules", - "you_are_aware_that_it_breaks_specific_rules": "You are aware that it breaks specific rules", - "its_something_else": "It’s something else", - "the_issue_does_not_fit_into_other_categories": "The issue does not fit into other categories" + "step_1_of_4": "Cam 1 o 4", + "whats_wrong_with_this_post": "Beth sy'n bod gyda'r tŵt hwn?", + "whats_wrong_with_this_account": "Beth sy'n bod gyda'r cyfrif hwn?", + "whats_wrong_with_this_username": "Beth sy'n bod gyda %s?", + "select_the_best_match": "Dewiswch yr opsiwn gorau", + "i_dont_like_it": "Dydw i ddim yn ei hoffi", + "it_is_not_something_you_want_to_see": "Nid yw'n rhywbeth ydych chi eisiau ei weld", + "its_spam": "Mae'n sbam", + "malicious_links_fake_engagement_or_repetetive_replies": "Dolenni maleisus, ymgysylltu ffug, neu ymatebion ailadroddus", + "it_violates_server_rules": "Mae'n torri rheolau'r gweinydd", + "you_are_aware_that_it_breaks_specific_rules": "Rydych yn ymwybodol ei fod yn torri rheolau penodol", + "its_something_else": "Mae'n rhywbeth arall", + "the_issue_does_not_fit_into_other_categories": "Nid yw'r mater yn ffitio i gategorïau eraill" }, "step_two": { - "step_2_of_4": "Step 2 of 4", - "which_rules_are_being_violated": "Which rules are being violated?", - "select_all_that_apply": "Select all that apply", - "i_just_don’t_like_it": "I just don’t like it" + "step_2_of_4": "Cam 2 o 4", + "which_rules_are_being_violated": "Pa reolau sy'n cael eu torri?", + "select_all_that_apply": "Dewiswch bob un sy'n berthnasol", + "i_just_don’t_like_it": "Dydw i ddim yn ei hoffi" }, "step_three": { - "step_3_of_4": "Step 3 of 4", - "are_there_any_posts_that_back_up_this_report": "Are there any posts that back up this report?", - "select_all_that_apply": "Select all that apply" + "step_3_of_4": "Cam 3 o 4", + "are_there_any_posts_that_back_up_this_report": "Oes postiadau eraill sy'n cefnogi'r adroddiad hwn?", + "select_all_that_apply": "Dewiswch bob un sy'n berthnasol" }, "step_four": { - "step_4_of_4": "Step 4 of 4", - "is_there_anything_else_we_should_know": "Is there anything else we should know?" + "step_4_of_4": "Cam 4 o 4", + "is_there_anything_else_we_should_know": "Oes unrhyw beth arall y dylem ei wybod?" }, "step_final": { - "dont_want_to_see_this": "Don’t want to see this?", - "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", - "unfollow": "Unfollow", - "unfollowed": "Unfollowed", - "unfollow_user": "Unfollow %s", - "mute_user": "Mute %s", - "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", - "block_user": "Block %s", - "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.", - "while_we_review_this_you_can_take_action_against_user": "While we review this, you can take action against %s" + "dont_want_to_see_this": "Ddim eisiau gweld hwn?", + "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "Pan welwch chi gynnwys nad ydych chi'n ei hoffi ar Mastodon, gallwch dynnu'r person o'ch profiad.", + "unfollow": "Dad-ddilyn", + "unfollowed": "Dad-ddilynwyd", + "unfollow_user": "Dad-ddilyn %s", + "mute_user": "Anwybyddu %s", + "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "Ni fyddwch yn gweld eu postiadau neu hybiau yn eich ffrwd hafan. Ni fyddant yn gwybod eich bod wedi eu hanwybyddu.", + "block_user": "Blocio %s", + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "Ni fyddant yn gallu eich dilyn neu weld eich postiadau, ond maen nhw'n gallu gweld eich bod wedi'u blocio.", + "while_we_review_this_you_can_take_action_against_user": "Tra byddwn ni'n edrych ar hyn, gallwch gymryd camau yn erbyn %s" } }, "preview": { "keyboard": { - "close_preview": "Close Preview", - "show_next": "Show Next", - "show_previous": "Show Previous" + "close_preview": "Cau Rhagolwg", + "show_next": "Dangos Nesaf", + "show_previous": "Dangos Blaenorol" } }, "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": "Proffil cyfredol: %s. Tapiwch dwywaith a gwasgu i ddefnyddio'r newidiwr cyfrifon", + "dismiss_account_switcher": "Diddymu Newidiwr Cyfrifon", + "add_account": "Ychwanegu Cyfrif" }, "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": "Newydd i Mastodon", + "multiple_account_switch_intro_description": "Newid rhwng cyfrifon gwahanol wrth wasgu'r botwm proffil.", + "accessibility_hint": "Tapiwch dwywaith i ddiddymu'r dewin hwn" }, "bookmark": { - "title": "Bookmarks" + "title": "Tudalnodau" + }, + "followed_tags": { + "title": "Tagiau a Ddilynwyd", + "header": { + "posts": "postiadau", + "participants": "cyfranwyr", + "posts_today": "postiadau heddiw" + }, + "actions": { + "follow": "Dilyn", + "unfollow": "Dad-ddilyn" + } } } } diff --git a/Localization/StringsConvertor/input/cy.lproj/ios-infoPlist.json b/Localization/StringsConvertor/input/cy.lproj/ios-infoPlist.json index ee0c5bfee..e2a58387a 100644 --- a/Localization/StringsConvertor/input/cy.lproj/ios-infoPlist.json +++ b/Localization/StringsConvertor/input/cy.lproj/ios-infoPlist.json @@ -1,6 +1,6 @@ { - "NSCameraUsageDescription": "Used to take photo for post status", - "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library", + "NSCameraUsageDescription": "Defnyddir hwn i gymryd llun am bost", + "NSPhotoLibraryAddUsageDescription": "Defnyddir hwn i gadw llun yn eich Photo Library", "NewPostShortcutItemTitle": "Post Newydd", "SearchShortcutItemTitle": "Chwilio" } diff --git a/Localization/StringsConvertor/input/da.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/da.lproj/Localizable.stringsdict index eabdc3c32..788eb95fc 100644 --- a/Localization/StringsConvertor/input/da.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/da.lproj/Localizable.stringsdict @@ -15,7 +15,7 @@ one 1 unread notification other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds diff --git a/Localization/StringsConvertor/input/da.lproj/app.json b/Localization/StringsConvertor/input/da.lproj/app.json index 3113ada74..4939d3afb 100644 --- a/Localization/StringsConvertor/input/da.lproj/app.json +++ b/Localization/StringsConvertor/input/da.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Clean Cache", "message": "Successfully cleaned %s cache." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Create account", "see_more": "See More", "preview": "Preview", + "copy": "Copy", "share": "Share", "share_user": "Share %s", "share_post": "Share Post", @@ -91,12 +97,16 @@ "block_domain": "Block %s", "unblock_domain": "Unblock %s", "settings": "Settings", - "delete": "Delete" + "delete": "Delete", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Home", - "search": "Search", - "notification": "Notification", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Profile" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Sensitive Content", "media_content_warning": "Tap anywhere to reveal", "tap_to_reveal": "Tap to reveal", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Vote", "closed": "Closed" @@ -153,6 +165,7 @@ "show_image": "Show image", "show_gif": "Show GIF", "show_video_player": "Show video player", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Add Row", "placeholder": { "label": "Label", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/de.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/de.lproj/Localizable.stringsdict index 1965fd02b..9d07f80d1 100644 --- a/Localization/StringsConvertor/input/de.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/de.lproj/Localizable.stringsdict @@ -37,7 +37,7 @@ a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Noch %#@character_count@ übrig + Noch %#@character_count@ Zeichen übrig character_count NSStringFormatSpecTypeKey @@ -53,7 +53,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + %#@character_count@ übrig character_count NSStringFormatSpecTypeKey @@ -61,9 +61,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 Zeichen other - %ld characters + %ld Zeichen plural.count.followed_by_and_mutual diff --git a/Localization/StringsConvertor/input/de.lproj/app.json b/Localization/StringsConvertor/input/de.lproj/app.json index 894a0245e..8c28db94f 100644 --- a/Localization/StringsConvertor/input/de.lproj/app.json +++ b/Localization/StringsConvertor/input/de.lproj/app.json @@ -45,12 +45,17 @@ "message": "Bitte aktiviere den Zugriff auf die Fotobibliothek, um das Foto zu speichern." }, "delete_post": { - "title": "Bist du dir sicher, dass du diesen Beitrag löschen möchtest?", + "title": "Beiträge löschen", "message": "Bist du dir sicher, dass du diesen Beitrag löschen willst?" }, "clean_cache": { "title": "Zwischenspeicher leeren", "message": "%s erfolgreich aus dem Cache gelöscht." + }, + "translation_failed": { + "title": "Hinweis", + "message": "Übersetzung fehlgeschlagen. Möglicherweise hat der/die Administrator*in die Übersetzungen auf diesem Server nicht aktiviert oder dieser Server läuft mit einer älteren Version von Mastodon, in der Übersetzungen noch nicht unterstützt wurden.", + "button": "OK" } }, "controls": { @@ -66,7 +71,7 @@ "ok": "OK", "done": "Fertig", "confirm": "Bestätigen", - "continue": "Fortfahren", + "continue": "Weiter", "compose": "Neue Nachricht", "cancel": "Abbrechen", "discard": "Verwerfen", @@ -78,12 +83,13 @@ "sign_up": "Konto erstellen", "see_more": "Mehr anzeigen", "preview": "Vorschau", + "copy": "Kopieren", "share": "Teilen", "share_user": "%s teilen", "share_post": "Beitrag teilen", "open_in_safari": "In Safari öffnen", "open_in_browser": "Im Browser anzeigen", - "find_people": "Finde Personen zum Folgen", + "find_people": "Personen zum Folgen finden", "manually_search": "Stattdessen manuell suchen", "skip": "Überspringen", "reply": "Antworten", @@ -91,12 +97,16 @@ "block_domain": "%s blockieren", "unblock_domain": "Blockierung von %s aufheben", "settings": "Einstellungen", - "delete": "Löschen" + "delete": "Löschen", + "translate_post": { + "title": "Von %s übersetzen", + "unknown_language": "Unbekannt" + } }, "tabs": { "home": "Startseite", - "search": "Suche", - "notification": "Benachrichtigungen", + "search_and_explore": "Suchen und Entdecken", + "notifications": "Mitteilungen", "profile": "Profil" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "NSFW-Inhalt", "media_content_warning": "Tippe irgendwo zum Anzeigen", "tap_to_reveal": "Zum Anzeigen tippen", + "load_embed": "Eingebettetes laden", + "link_via_user": "%s via %s", "poll": { "vote": "Abstimmen", "closed": "Beendet" @@ -139,8 +151,8 @@ "meta_entity": { "url": "Link: %s", "hashtag": "Hashtag: %s", - "mention": "Show Profile: %s", - "email": "Email address: %s" + "mention": "Profil anzeigen: %s", + "email": "E-Mail-Adresse: %s" }, "actions": { "reply": "Antworten", @@ -153,6 +165,7 @@ "show_image": "Bild anzeigen", "show_gif": "GIF anzeigen", "show_video_player": "Zeige Video-Player", + "share_link_in_post": "Link im Beitrag teilen", "tap_then_hold_to_show_menu": "Halte gedrückt um das Menü anzuzeigen" }, "tag": { @@ -165,14 +178,20 @@ }, "visibility": { "unlisted": "Jeder kann diesen Post sehen, aber nicht in der öffentlichen Timeline zeigen.", - "private": "Nur Follower des Authors können diesen Beitrag sehen.", - "private_from_me": "Nur meine Follower können diesen Beitrag sehen.", + "private": "Nur die, die dem Autor folgen, können diesen Beitrag sehen.", + "private_from_me": "Nur die, die mir folgen, können diesen Beitrag sehen.", "direct": "Nur erwähnte Benutzer können diesen Beitrag sehen." + }, + "translation": { + "translated_from": "Übersetzt von %s mit %s", + "unknown_language": "Unbekannt", + "unknown_provider": "Unbekannt", + "show_original": "Original anzeigen" } }, "friendship": { "follow": "Folgen", - "following": "Folge Ich", + "following": "Gefolgt", "request": "Anfragen", "pending": "In Warteschlange", "block": "Blockieren", @@ -187,8 +206,8 @@ "unmute_user": "%s nicht mehr stummschalten", "muted": "Stummgeschaltet", "edit_info": "Information bearbeiten", - "show_reblogs": "Reblogs anzeigen", - "hide_reblogs": "Reblogs ausblenden" + "show_reblogs": "Teilen anzeigen", + "hide_reblogs": "Teilen ausblenden" }, "timeline": { "filtered": "Gefiltert", @@ -197,7 +216,7 @@ }, "loader": { "load_missing_posts": "Fehlende Beiträge laden", - "loading_missing_posts": "Lade fehlende Beiträge...", + "loading_missing_posts": "Fehlende Beiträge werden geladen …", "show_more_replies": "Weitere Antworten anzeigen" }, "header": { @@ -257,7 +276,7 @@ "search_servers_or_enter_url": "Suche nach einer Community oder gib eine URL ein" }, "empty_state": { - "finding_servers": "Verfügbare Server werden gesucht...", + "finding_servers": "Verfügbare Server werden gesucht …", "bad_network": "Beim Laden der Daten ist etwas schief gelaufen. Überprüfe deine Internetverbindung.", "no_results": "Keine Ergebnisse" } @@ -348,7 +367,7 @@ "open_email_app": { "title": "Überprüfe deinen Posteingang.", "description": "Wir haben dir gerade eine E-Mail geschickt. Überprüfe deinen Spam-Ordner, falls du es noch nicht getan hast.", - "mail": "Mail", + "mail": "E-Mail", "open_email_client": "E-Mail-Client öffnen" } }, @@ -358,7 +377,7 @@ "offline": "Offline", "new_posts": "Neue Beiträge anzeigen", "published": "Veröffentlicht!", - "Publishing": "Beitrag wird veröffentlicht...", + "Publishing": "Beitrag wird veröffentlicht …", "accessibility": { "logo_label": "Logo-Button", "logo_hint": "Zum Scrollen nach oben tippen und zum vorherigen Ort erneut tippen" @@ -367,7 +386,7 @@ }, "suggestion_account": { "title": "Finde Personen zum Folgen", - "follow_explain": "Wenn du jemandem folgst, dann siehst du deren Beiträge in deinem Home-Feed." + "follow_explain": "Sobald du anderen folgst, siehst du deren Beiträge in deinem Home-Feed." }, "compose": { "title": { @@ -386,14 +405,14 @@ "photo": "Foto", "video": "Video", "attachment_broken": "Dieses %s scheint defekt zu sein und\nkann nicht auf Mastodon hochgeladen werden.", - "description_photo": "Für Menschen mit Sehbehinderung beschreiben...", - "description_video": "Für Menschen mit Sehbehinderung beschreiben...", + "description_photo": "Für Menschen mit Sehbehinderung beschreiben …", + "description_video": "Für Menschen mit Sehbehinderung beschreiben …", "load_failed": "Laden fehlgeschlagen", "upload_failed": "Upload fehlgeschlagen", "can_not_recognize_this_media_attachment": "Medienanhang wurde nicht erkannt", "attachment_too_large": "Anhang zu groß", - "compressing_state": "Komprimieren...", - "server_processing_state": "Serververarbeitung..." + "compressing_state": "wird komprimiert …", + "server_processing_state": "Serververarbeitung …" }, "poll": { "duration_time": "Dauer: %s", @@ -408,7 +427,7 @@ "the_poll_has_empty_option": "Die Umfrage hat eine leere Option" }, "content_warning": { - "placeholder": "Schreibe eine Inhaltswarnung hier..." + "placeholder": "Hier eine Inhaltswarnung schreiben …" }, "visibility": { "public": "Öffentlich", @@ -427,8 +446,8 @@ "enable_content_warning": "Inhaltswarnung einschalten", "disable_content_warning": "Inhaltswarnung ausschalten", "post_visibility_menu": "Sichtbarkeitsmenü", - "post_options": "Post Options", - "posting_as": "Posting as %s" + "post_options": "Beitragsoptionen", + "posting_as": "Veröffentlichen als %s" }, "keyboard": { "discard_post": "Beitrag verwerfen", @@ -444,11 +463,15 @@ "follows_you": "Folgt dir" }, "dashboard": { - "posts": "Beiträge", - "following": "Gefolgte", - "followers": "Folgende" + "my_posts": "Beiträge", + "my_following": "folge ich", + "my_followers": "followers", + "other_posts": "Beiträge", + "other_following": "folge ich", + "other_followers": "followers" }, "fields": { + "joined": "Beigetreten", "add_row": "Zeile hinzufügen", "placeholder": { "label": "Bezeichnung", @@ -484,12 +507,12 @@ "message": "Bestätige %s zu entsperren" }, "confirm_show_reblogs": { - "title": "Reblogs anzeigen", - "message": "Bestätigen um Reblogs anzuzeigen" + "title": "Teilen anzeigen", + "message": "Bestätigen, um Teilen anzuzeigen" }, "confirm_hide_reblogs": { - "title": "Reblogs ausblenden", - "message": "Confirm to hide reblogs" + "title": "Teilen ausblenden", + "message": "Bestätigen, um Teilen auszublenden" } }, "accessibility": { @@ -500,15 +523,15 @@ } }, "follower": { - "title": "Follower", - "footer": "Folger, die nicht auf deinem Server registriert sind, werden nicht angezeigt." + "title": "Folgende", + "footer": "Folgende, die nicht auf deinem Server registriert sind, werden nicht angezeigt." }, "following": { - "title": "Folgende", + "title": "Gefolgte", "footer": "Gefolgte, die nicht auf deinem Server registriert sind, werden nicht angezeigt." }, "familiarFollowers": { - "title": "Follower, die dir bekannt vorkommen", + "title": "Folgende, die du kennst", "followed_by_names": "Gefolgt von %s" }, "favorited_by": { @@ -532,7 +555,7 @@ }, "accounts": { "title": "Konten, die dir gefallen könnten", - "description": "Vielleicht gefallen dir diese Benutzer", + "description": "Vielleicht gefallen dir diese Konten", "follow": "Folgen" } }, @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Lesezeichen" + }, + "followed_tags": { + "title": "Gefolgte Hashtags", + "header": { + "posts": "Beiträge", + "participants": "Teilnehmer*innen", + "posts_today": "Beiträge heute" + }, + "actions": { + "follow": "Folgen", + "unfollow": "Entfolgen" + } } } } diff --git a/Localization/StringsConvertor/input/en-US.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/en-US.lproj/Localizable.stringsdict index eabdc3c32..788eb95fc 100644 --- a/Localization/StringsConvertor/input/en-US.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/en-US.lproj/Localizable.stringsdict @@ -15,7 +15,7 @@ one 1 unread notification other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds diff --git a/Localization/StringsConvertor/input/en-US.lproj/app.json b/Localization/StringsConvertor/input/en-US.lproj/app.json index 3113ada74..b94b9df8a 100644 --- a/Localization/StringsConvertor/input/en-US.lproj/app.json +++ b/Localization/StringsConvertor/input/en-US.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Clean Cache", "message": "Successfully cleaned %s cache." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Create account", "see_more": "See More", "preview": "Preview", + "copy": "Copy", "share": "Share", "share_user": "Share %s", "share_post": "Share Post", @@ -91,12 +97,16 @@ "block_domain": "Block %s", "unblock_domain": "Unblock %s", "settings": "Settings", - "delete": "Delete" + "delete": "Delete", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Home", - "search": "Search", - "notification": "Notification", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Profile" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Sensitive Content", "media_content_warning": "Tap anywhere to reveal", "tap_to_reveal": "Tap to reveal", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Vote", "closed": "Closed" @@ -153,6 +165,7 @@ "show_image": "Show image", "show_gif": "Show GIF", "show_video_player": "Show video player", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -360,7 +379,7 @@ "published": "Published!", "Publishing": "Publishing post...", "accessibility": { - "logo_label": "Logo Button", + "logo_label": "Mastodon", "logo_hint": "Tap to scroll to top and tap again to previous location" } } @@ -444,11 +463,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Add Row", "placeholder": { "label": "Label", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/en.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/en.lproj/Localizable.stringsdict index 297e6675a..788eb95fc 100644 --- a/Localization/StringsConvertor/input/en.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/en.lproj/Localizable.stringsdict @@ -15,7 +15,7 @@ one 1 unread notification other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds @@ -60,14 +60,8 @@ NSStringPluralRuleType NSStringFormatValueTypeKey ld - zero - no characters one 1 character - few - %ld characters - many - %ld characters other %ld characters diff --git a/Localization/StringsConvertor/input/en.lproj/app.json b/Localization/StringsConvertor/input/en.lproj/app.json index 3113ada74..b94b9df8a 100644 --- a/Localization/StringsConvertor/input/en.lproj/app.json +++ b/Localization/StringsConvertor/input/en.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Clean Cache", "message": "Successfully cleaned %s cache." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Create account", "see_more": "See More", "preview": "Preview", + "copy": "Copy", "share": "Share", "share_user": "Share %s", "share_post": "Share Post", @@ -91,12 +97,16 @@ "block_domain": "Block %s", "unblock_domain": "Unblock %s", "settings": "Settings", - "delete": "Delete" + "delete": "Delete", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Home", - "search": "Search", - "notification": "Notification", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Profile" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Sensitive Content", "media_content_warning": "Tap anywhere to reveal", "tap_to_reveal": "Tap to reveal", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Vote", "closed": "Closed" @@ -153,6 +165,7 @@ "show_image": "Show image", "show_gif": "Show GIF", "show_video_player": "Show video player", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -360,7 +379,7 @@ "published": "Published!", "Publishing": "Publishing post...", "accessibility": { - "logo_label": "Logo Button", + "logo_label": "Mastodon", "logo_hint": "Tap to scroll to top and tap again to previous location" } } @@ -444,11 +463,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Add Row", "placeholder": { "label": "Label", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/es-AR.lproj/app.json b/Localization/StringsConvertor/input/es-AR.lproj/app.json index 5be543f98..120460c44 100644 --- a/Localization/StringsConvertor/input/es-AR.lproj/app.json +++ b/Localization/StringsConvertor/input/es-AR.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Limpiar caché", "message": "Se limpió exitosamente %s de la memoria caché." + }, + "translation_failed": { + "title": "Nota", + "message": "Falló la traducción. Tal vez el administrador no habilitó las traducciones en este servidor, o este servidor está ejecutando una versión antigua de Mastodon en donde las traducciones aún no estaban disponibles.", + "button": "Aceptar" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Crear cuenta", "see_more": "Ver más", "preview": "Previsualización", + "copy": "Copiar", "share": "Compartir", "share_user": "Compartir %s", "share_post": "Compartir mensaje", @@ -91,12 +97,16 @@ "block_domain": "Bloquear a %s", "unblock_domain": "Desbloquear a %s", "settings": "Configuración", - "delete": "Eliminar" + "delete": "Eliminar", + "translate_post": { + "title": "Traducido desde el %s", + "unknown_language": "Desconocido" + } }, "tabs": { "home": "Principal", - "search": "Buscar", - "notification": "Notificación", + "search_and_explore": "Buscar y explorar", + "notifications": "Notificaciones", "profile": "Perfil" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Contenido sensible", "media_content_warning": "Tocá en cualquier parte para mostrar", "tap_to_reveal": "Tocá para mostrar", + "load_embed": "Cargar lo insertado", + "link_via_user": "%s vía %s", "poll": { "vote": "Votar", "closed": "Cerrada" @@ -153,6 +165,7 @@ "show_image": "Mostrar imagen", "show_gif": "Mostrar GIF", "show_video_player": "Mostrar reproductor de video", + "share_link_in_post": "Compartir enlace en mensaje", "tap_then_hold_to_show_menu": "Tocá y mantené presionado para mostrar el menú" }, "tag": { @@ -168,6 +181,12 @@ "private": "Sólo sus seguidores pueden ver este mensaje.", "private_from_me": "Sólo mis seguidores pueden ver este mensaje.", "direct": "Sólo el usuario mencionado puede ver este mensaje." + }, + "translation": { + "translated_from": "Traducido desde el %s vía %s", + "unknown_language": "Desconocido", + "unknown_provider": "Desconocido", + "show_original": "Mostrar original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Te sigue" }, "dashboard": { - "posts": "mensajes", - "following": "siguiendo", - "followers": "seguidores" + "my_posts": "mensajes", + "my_following": "siguiendo", + "my_followers": "seguidores", + "other_posts": "mensajes", + "other_following": "siguiendo", + "other_followers": "seguidores" }, "fields": { + "joined": "En este servidor desde", "add_row": "Agregar fila", "placeholder": { "label": "Nombre de campo", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Marcadores" + }, + "followed_tags": { + "title": "Etiquetas seguidas", + "header": { + "posts": "mensajes", + "participants": "participantes", + "posts_today": "mensajes hoy" + }, + "actions": { + "follow": "Seguir", + "unfollow": "Dejar de seguir" + } } } } diff --git a/Localization/StringsConvertor/input/es.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/es.lproj/Localizable.stringsdict index ca07b6b28..0a904fcfd 100644 --- a/Localization/StringsConvertor/input/es.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/es.lproj/Localizable.stringsdict @@ -53,7 +53,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + Quedan %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -61,9 +61,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 carácter other - %ld characters + %ld caracteres plural.count.followed_by_and_mutual diff --git a/Localization/StringsConvertor/input/es.lproj/app.json b/Localization/StringsConvertor/input/es.lproj/app.json index 1b90bfa10..6d19e833b 100644 --- a/Localization/StringsConvertor/input/es.lproj/app.json +++ b/Localization/StringsConvertor/input/es.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Limpiar Caché", "message": "Se han limpiado con éxito %s de caché." + }, + "translation_failed": { + "title": "Nota", + "message": "Error al traducir. Tal vez el administrador no ha habilitado las traducciones en este servidor o este servidor está ejecutando una versión antigua de Mastodon donde las traducciones aún no están soportadas.", + "button": "Aceptar" } }, "controls": { @@ -74,10 +79,11 @@ "take_photo": "Tomar foto", "save_photo": "Guardar foto", "copy_photo": "Copiar foto", - "sign_in": "Log in", - "sign_up": "Create account", + "sign_in": "Iniciar sesión", + "sign_up": "Crear cuenta", "see_more": "Ver más", "preview": "Vista previa", + "copy": "Copiar", "share": "Compartir", "share_user": "Compartir %s", "share_post": "Compartir publicación", @@ -91,12 +97,16 @@ "block_domain": "Bloquear %s", "unblock_domain": "Desbloquear %s", "settings": "Configuración", - "delete": "Borrar" + "delete": "Borrar", + "translate_post": { + "title": "Traducir desde %s", + "unknown_language": "Desconocido" + } }, "tabs": { "home": "Inicio", - "search": "Buscar", - "notification": "Notificación", + "search_and_explore": "Buscar y explorar", + "notifications": "Notificaciones", "profile": "Perfil" }, "keyboard": { @@ -132,15 +142,17 @@ "sensitive_content": "Contenido sensible", "media_content_warning": "Pulsa en cualquier sitio para mostrar", "tap_to_reveal": "Tocar para revelar", + "load_embed": "Cargar incrustado", + "link_via_user": "%s vía %s", "poll": { "vote": "Vota", "closed": "Cerrado" }, "meta_entity": { - "url": "Link: %s", - "hashtag": "Hashtag: %s", - "mention": "Show Profile: %s", - "email": "Email address: %s" + "url": "Enlace: %s", + "hashtag": "Etiqueta: %s", + "mention": "Mostrar Perfil: %s", + "email": "Dirección de correo electrónico: %s" }, "actions": { "reply": "Responder", @@ -153,6 +165,7 @@ "show_image": "Mostrar imagen", "show_gif": "Mostrar GIF", "show_video_player": "Mostrar reproductor de vídeo", + "share_link_in_post": "Compartir enlace en publicación", "tap_then_hold_to_show_menu": "Toca, después mantén para mostrar el menú" }, "tag": { @@ -168,6 +181,12 @@ "private": "Sólo sus seguidores pueden ver este mensaje.", "private_from_me": "Sólo mis seguidores pueden ver este mensaje.", "direct": "Sólo el usuario mencionado puede ver este mensaje." + }, + "translation": { + "translated_from": "Traducido desde %s usando %s", + "unknown_language": "Desconocido", + "unknown_provider": "Desconocido", + "show_original": "Mostrar Original" } }, "friendship": { @@ -187,8 +206,8 @@ "unmute_user": "Desmutear a %s", "muted": "Silenciado", "edit_info": "Editar Info", - "show_reblogs": "Show Reblogs", - "hide_reblogs": "Hide Reblogs" + "show_reblogs": "Mostrar reblogs", + "hide_reblogs": "Ocultar reblogs" }, "timeline": { "filtered": "Filtrado", @@ -219,15 +238,15 @@ "log_in": "Iniciar sesión" }, "login": { - "title": "Welcome back", - "subtitle": "Log you in on the server you created your account on.", + "title": "Bienvenido de nuevo", + "subtitle": "Inicie sesión en el servidor en el que creó su cuenta.", "server_search_field": { - "placeholder": "Enter URL or search for your server" + "placeholder": "Introduzca la URL o busque su servidor" } }, "server_picker": { "title": "Elige un servidor,\ncualquier servidor.", - "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.", + "subtitle": "Escoge un servidor basado en tu región, intereses o un propósito general. Aún puedes chatear con cualquiera en Mastodon, independientemente de tus servidores.", "button": { "category": { "all": "Todas", @@ -254,7 +273,7 @@ "category": "CATEGORÍA" }, "input": { - "search_servers_or_enter_url": "Search communities or enter URL" + "search_servers_or_enter_url": "Buscar comunidades o introducir URL" }, "empty_state": { "finding_servers": "Encontrando servidores disponibles...", @@ -388,12 +407,12 @@ "attachment_broken": "Este %s está roto y no puede\nsubirse a Mastodon.", "description_photo": "Describe la foto para los usuarios con dificultad visual...", "description_video": "Describe el vídeo para los usuarios con dificultad visual...", - "load_failed": "Load Failed", - "upload_failed": "Upload Failed", - "can_not_recognize_this_media_attachment": "Can not recognize this media attachment", - "attachment_too_large": "Attachment too large", - "compressing_state": "Compressing...", - "server_processing_state": "Server Processing..." + "load_failed": "Carga fallida", + "upload_failed": "Error al cargar", + "can_not_recognize_this_media_attachment": "No se puede reconocer este archivo adjunto", + "attachment_too_large": "Adjunto demasiado grande", + "compressing_state": "Comprimiendo...", + "server_processing_state": "Procesando en el servidor..." }, "poll": { "duration_time": "Duración: %s", @@ -404,8 +423,8 @@ "three_days": "4 Días", "seven_days": "7 Días", "option_number": "Opción %ld", - "the_poll_is_invalid": "The poll is invalid", - "the_poll_has_empty_option": "The poll has empty option" + "the_poll_is_invalid": "La encuesta no es válida", + "the_poll_has_empty_option": "La encuesta tiene una opción vacía" }, "content_warning": { "placeholder": "Escribe una advertencia precisa aquí..." @@ -427,8 +446,8 @@ "enable_content_warning": "Activar Advertencia de Contenido", "disable_content_warning": "Desactivar Advertencia de Contenido", "post_visibility_menu": "Menú de Visibilidad de la Publicación", - "post_options": "Post Options", - "posting_as": "Posting as %s" + "post_options": "Opciones de Publicación", + "posting_as": "Publicado como %s" }, "keyboard": { "discard_post": "Descartar Publicación", @@ -444,19 +463,23 @@ "follows_you": "Te sigue" }, "dashboard": { - "posts": "publicaciones", - "following": "siguiendo", - "followers": "seguidores" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Se unió", "add_row": "Añadir Fila", "placeholder": { "label": "Nombre para el campo", "content": "Contenido" }, "verified": { - "short": "Verified on %s", - "long": "Ownership of this link was checked on %s" + "short": "Verificado en %s", + "long": "La propiedad de este enlace fue verificada el %s" } }, "segmented_control": { @@ -484,12 +507,12 @@ "message": "Confirmar para desbloquear a %s" }, "confirm_show_reblogs": { - "title": "Show Reblogs", - "message": "Confirm to show reblogs" + "title": "Mostrar reblogs", + "message": "Confirmar para mostrar reblogs" }, "confirm_hide_reblogs": { - "title": "Hide Reblogs", - "message": "Confirm to hide reblogs" + "title": "Ocultar reblogs", + "message": "Confirmar para ocultar reblogs" } }, "accessibility": { @@ -721,7 +744,19 @@ "accessibility_hint": "Haz doble toque para descartar este asistente" }, "bookmark": { - "title": "Bookmarks" + "title": "Marcadores" + }, + "followed_tags": { + "title": "Etiquetas seguidas", + "header": { + "posts": "publicaciones", + "participants": "participantes", + "posts_today": "publicaciones de hoy" + }, + "actions": { + "follow": "Seguir", + "unfollow": "Dejar de seguir" + } } } } diff --git a/Localization/StringsConvertor/input/eu.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/eu.lproj/Localizable.stringsdict index 057ca4010..404deebd3 100644 --- a/Localization/StringsConvertor/input/eu.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/eu.lproj/Localizable.stringsdict @@ -63,13 +63,13 @@ one 1 character other - %ld characters + %ld karaktere plural.count.followed_by_and_mutual NSStringLocalizedFormatKey - %#@names@%#@count_mutual@ + %#@names@: "%#@count_mutual@ names one diff --git a/Localization/StringsConvertor/input/eu.lproj/app.json b/Localization/StringsConvertor/input/eu.lproj/app.json index 3da0d6a00..e7c5021bb 100644 --- a/Localization/StringsConvertor/input/eu.lproj/app.json +++ b/Localization/StringsConvertor/input/eu.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Garbitu cache-a", "message": "Behar bezala garbitu da %s cache-a." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -74,10 +79,11 @@ "take_photo": "Atera argazkia", "save_photo": "Gorde argazkia", "copy_photo": "Kopiatu argazkia", - "sign_in": "Log in", - "sign_up": "Create account", + "sign_in": "Hasi saioa", + "sign_up": "Sortu kontua", "see_more": "Ikusi gehiago", "preview": "Aurrebista", + "copy": "Copy", "share": "Partekatu", "share_user": "Partekatu %s", "share_post": "Partekatu bidalketa", @@ -91,12 +97,16 @@ "block_domain": "Blokeatu %s", "unblock_domain": "Desblokeatu %s", "settings": "Ezarpenak", - "delete": "Ezabatu" + "delete": "Ezabatu", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Hasiera", - "search": "Bilatu", - "notification": "Jakinarazpena", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Profila" }, "keyboard": { @@ -129,18 +139,20 @@ "show_post": "Erakutsi bidalketa", "show_user_profile": "Erakutsi erabiltzailearen profila", "content_warning": "Edukiaren abisua", - "sensitive_content": "Sensitive Content", + "sensitive_content": "Eduki hunkigarria", "media_content_warning": "Ukitu edonon bistaratzeko", "tap_to_reveal": "Sakatu erakusteko", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Bozkatu", "closed": "Itxita" }, "meta_entity": { - "url": "Link: %s", - "hashtag": "Hashtag: %s", - "mention": "Show Profile: %s", - "email": "Email address: %s" + "url": "Lotura: %s", + "hashtag": "Traolak: %s", + "mention": "Erakutsi Profila: %s", + "email": "E-posta helbidea: %s" }, "actions": { "reply": "Erantzun", @@ -153,6 +165,7 @@ "show_image": "Erakutsi irudia", "show_gif": "Erakutsi GIFa", "show_video_player": "Erakutsi bideo-erreproduzigailua", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Sakatu eta eutsi menua erakusteko" }, "tag": { @@ -168,6 +181,12 @@ "private": "Beren jarraitzaileek soilik ikus dezakete bidalketa hau.", "private_from_me": "Nire jarraitzaileek soilik ikus dezakete bidalketa hau.", "direct": "Aipatutako erabiltzaileek soilik ikus dezakete bidalketa hau." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -187,8 +206,8 @@ "unmute_user": "Desmututu %s", "muted": "Mutututa", "edit_info": "Editatu informazioa", - "show_reblogs": "Show Reblogs", - "hide_reblogs": "Hide Reblogs" + "show_reblogs": "Ikusi bultzadak", + "hide_reblogs": "Ezkutatu bultzadak" }, "timeline": { "filtered": "Iragazita", @@ -219,7 +238,7 @@ "log_in": "Hasi saioa" }, "login": { - "title": "Welcome back", + "title": "Ongi etorri berriro ere", "subtitle": "Log you in on the server you created your account on.", "server_search_field": { "placeholder": "Enter URL or search for your server" @@ -264,7 +283,7 @@ }, "register": { "title": "Hitz egin iezaguzu zuri buruz.", - "lets_get_you_set_up_on_domain": "Let’s get you set up on %s", + "lets_get_you_set_up_on_domain": "%s zerbitzariko kontua prestatuko dizugu", "input": { "avatar": { "delete": "Ezabatu" @@ -335,7 +354,7 @@ "confirm_email": { "title": "Eta azkenik...", "subtitle": "Sakatu epostaz bidali dizugun loturan zure kontua egiaztatzeko.", - "tap_the_link_we_emailed_to_you_to_verify_your_account": "Tap the link we emailed to you to verify your account", + "tap_the_link_we_emailed_to_you_to_verify_your_account": "Sakatu epostaz bidali dizugun loturan zure kontua egiaztatzeko", "button": { "open_email_app": "Ireki eposta aplikazioa", "resend": "Berbidali" @@ -360,7 +379,7 @@ "published": "Argitaratua!", "Publishing": "Bidalketa argitaratzen...", "accessibility": { - "logo_label": "Logo Button", + "logo_label": "Logo botoia", "logo_hint": "Tap to scroll to top and tap again to previous location" } } @@ -389,10 +408,10 @@ "description_photo": "Deskribatu argazkia ikusmen arazoak dituztenentzat...", "description_video": "Deskribatu bideoa ikusmen arazoak dituztenentzat...", "load_failed": "Load Failed", - "upload_failed": "Upload Failed", + "upload_failed": "Kargatzeak huts egin du", "can_not_recognize_this_media_attachment": "Can not recognize this media attachment", - "attachment_too_large": "Attachment too large", - "compressing_state": "Compressing...", + "attachment_too_large": "Eranskina handiegia da", + "compressing_state": "Konprimatzen...", "server_processing_state": "Server Processing..." }, "poll": { @@ -404,7 +423,7 @@ "three_days": "3 egun", "seven_days": "7 egun", "option_number": "%ld aukera", - "the_poll_is_invalid": "The poll is invalid", + "the_poll_is_invalid": "Inkesta ez da balekoa", "the_poll_has_empty_option": "The poll has empty option" }, "content_warning": { @@ -427,7 +446,7 @@ "enable_content_warning": "Gaitu edukiaren abisua", "disable_content_warning": "Desgaitu edukiaren abisua", "post_visibility_menu": "Bidalketaren ikusgaitasunaren menua", - "post_options": "Post Options", + "post_options": "Bildalketaren aukerak", "posting_as": "Posting as %s" }, "keyboard": { @@ -441,14 +460,18 @@ }, "profile": { "header": { - "follows_you": "Follows You" + "follows_you": "Jarraitzen zaitu" }, "dashboard": { - "posts": "bidalketa", - "following": "jarraitzen", - "followers": "jarraitzaile" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Gehitu errenkada", "placeholder": { "label": "Etiketa", @@ -456,7 +479,7 @@ }, "verified": { "short": "Verified on %s", - "long": "Ownership of this link was checked on %s" + "long": "Esteka honen jabetzaren egiaztaketa data: %s" } }, "segmented_control": { @@ -484,12 +507,12 @@ "message": "Berretsi %s desblokeatzea" }, "confirm_show_reblogs": { - "title": "Show Reblogs", - "message": "Confirm to show reblogs" + "title": "Ikusi bultzadak", + "message": "Berretsi birbidalketak ikustea" }, "confirm_hide_reblogs": { - "title": "Hide Reblogs", - "message": "Confirm to hide reblogs" + "title": "Ezkutatu bultzadak", + "message": "Berretsi birbidalketak ezkutatzea" } }, "accessibility": { @@ -500,11 +523,11 @@ } }, "follower": { - "title": "follower", + "title": "jarraitzaile", "footer": "Beste zerbitzarietako jarraitzaileak ez dira bistaratzen." }, "following": { - "title": "following", + "title": "jarraitzen", "footer": "Beste zerbitzarietan jarraitutakoak ez dira bistaratzen." }, "familiarFollowers": { @@ -555,10 +578,10 @@ "posts": "Argitalpenak", "hashtags": "Traolak", "news": "Albisteak", - "community": "Community", + "community": "Komunitatea", "for_you": "Zuretzat" }, - "intro": "These are the posts gaining traction in your corner of Mastodon." + "intro": "Hauek dira zure Mastodon txokoan beraien lekua hartzen ari diren argitalpenak." }, "favorite": { "title": "Zure gogokoak" @@ -581,10 +604,10 @@ "show_mentions": "Erakutsi aipamenak" }, "follow_request": { - "accept": "Accept", - "accepted": "Accepted", - "reject": "reject", - "rejected": "Rejected" + "accept": "Onartu", + "accepted": "Onartuta", + "reject": "ukatu", + "rejected": "Ukatua" } }, "thread": { @@ -661,46 +684,46 @@ "text_placeholder": "Idatzi edo itsatsi iruzkin gehigarriak", "reported": "SALATUA", "step_one": { - "step_1_of_4": "Step 1 of 4", - "whats_wrong_with_this_post": "What's wrong with this post?", - "whats_wrong_with_this_account": "What's wrong with this account?", - "whats_wrong_with_this_username": "What's wrong with %s?", - "select_the_best_match": "Select the best match", - "i_dont_like_it": "I don’t like it", - "it_is_not_something_you_want_to_see": "It is not something you want to see", - "its_spam": "It’s spam", - "malicious_links_fake_engagement_or_repetetive_replies": "Malicious links, fake engagement, or repetetive replies", - "it_violates_server_rules": "It violates server rules", - "you_are_aware_that_it_breaks_specific_rules": "You are aware that it breaks specific rules", - "its_something_else": "It’s something else", - "the_issue_does_not_fit_into_other_categories": "The issue does not fit into other categories" + "step_1_of_4": "1. urratsa 4tik", + "whats_wrong_with_this_post": "Zer du txarra argitalpen honek?", + "whats_wrong_with_this_account": "Zer du txarra kontu honek?", + "whats_wrong_with_this_username": "Zer du txarra %s?", + "select_the_best_match": "Aukeratu egokiena", + "i_dont_like_it": "Ez dut gustukoa", + "it_is_not_something_you_want_to_see": "Ikusi nahi ez dudan zerbait da", + "its_spam": "Spama da", + "malicious_links_fake_engagement_or_repetetive_replies": "Esteka maltzurrak, gezurrezko elkarrekintzak edo erantzun errepikakorrak", + "it_violates_server_rules": "Zerbitzariaren arauak hausten ditu", + "you_are_aware_that_it_breaks_specific_rules": "Arau zehatzak urratzen dituela badakizu", + "its_something_else": "Beste zerbait da", + "the_issue_does_not_fit_into_other_categories": "Arazoa ezin da beste kategorietan sailkatu" }, "step_two": { - "step_2_of_4": "Step 2 of 4", - "which_rules_are_being_violated": "Which rules are being violated?", - "select_all_that_apply": "Select all that apply", + "step_2_of_4": "2. urratsa 4tik", + "which_rules_are_being_violated": "Ze arau hautsi ditu?", + "select_all_that_apply": "Hautatu dagozkion guztiak", "i_just_don’t_like_it": "I just don’t like it" }, "step_three": { - "step_3_of_4": "Step 3 of 4", - "are_there_any_posts_that_back_up_this_report": "Are there any posts that back up this report?", - "select_all_that_apply": "Select all that apply" + "step_3_of_4": "3. urratsa 4tik", + "are_there_any_posts_that_back_up_this_report": "Salaketa hau babesten duen bidalketarik badago?", + "select_all_that_apply": "Hautatu dagozkion guztiak" }, "step_four": { - "step_4_of_4": "Step 4 of 4", - "is_there_anything_else_we_should_know": "Is there anything else we should know?" + "step_4_of_4": "4. urratsa 4tik", + "is_there_anything_else_we_should_know": "Beste zerbait jakin beharko genuke?" }, "step_final": { - "dont_want_to_see_this": "Don’t want to see this?", - "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", - "unfollow": "Unfollow", + "dont_want_to_see_this": "Ez duzu hau ikusi nahi?", + "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "Mastodonen gustuko ez duzun zerbait ikusten duzunean, zure esperientziatik atera dezakezu pertsona hori.", + "unfollow": "Utzi jarraitzeari", "unfollowed": "Unfollowed", - "unfollow_user": "Unfollow %s", - "mute_user": "Mute %s", - "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", - "block_user": "Block %s", - "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.", - "while_we_review_this_you_can_take_action_against_user": "While we review this, you can take action against %s" + "unfollow_user": "%s jarraitzeari utzi", + "mute_user": "Mututu %s", + "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "Ez dituzu bere bidalketa eta birbidalketak zure hasierako jarioan ikusiko. Ez dute jakingo isilarazi dituztenik.", + "block_user": "Blokeatu %s", + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "Ezin izango dituzte zure bidalketak jarraitu edo ikusi, baina blokeatuta dauden ikusi ahal izango dute.", + "while_we_review_this_you_can_take_action_against_user": "Hau berrikusten dugun bitartean, %s erabiltzailearen aurkako neurriak hartu ditzakezu" } }, "preview": { @@ -721,7 +744,19 @@ "accessibility_hint": "Ukitu birritan morroi hau baztertzeko" }, "bookmark": { - "title": "Bookmarks" + "title": "Laster-markak" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/fi.lproj/app.json b/Localization/StringsConvertor/input/fi.lproj/app.json index 7dafe7fd1..f6beff049 100644 --- a/Localization/StringsConvertor/input/fi.lproj/app.json +++ b/Localization/StringsConvertor/input/fi.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Puhdista välimuisti", "message": "%s välimuisti tyhjennetty onnistuneesti." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Create account", "see_more": "Näytä lisää", "preview": "Esikatselu", + "copy": "Copy", "share": "Jaa", "share_user": "Jaa %s", "share_post": "Jaa julkaisu", @@ -91,12 +97,16 @@ "block_domain": "Estä %s", "unblock_domain": "Poista esto %s", "settings": "Asetukset", - "delete": "Poista" + "delete": "Poista", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Koti", - "search": "Haku", - "notification": "Ilmoitus", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Profiili" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Sensitive Content", "media_content_warning": "Napauta mistä tahansa paljastaaksesi", "tap_to_reveal": "Tap to reveal", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Vote", "closed": "Suljettu" @@ -153,6 +165,7 @@ "show_image": "Show image", "show_gif": "Show GIF", "show_video_player": "Show video player", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "Käännetty kielestä %s palvelulla %s", + "unknown_language": "Unknown", + "unknown_provider": "Tuntematon", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "julkaisut", - "following": "seurataan", - "followers": "seuraajat" + "my_posts": "julkaisut", + "my_following": "seurattavat", + "my_followers": "seuraajat", + "other_posts": "julkaisut", + "other_following": "seurattavat", + "other_followers": "seuraajat" }, "fields": { + "joined": "Joined", "add_row": "Lisää rivi", "placeholder": { "label": "Nimi", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/fr.lproj/app.json b/Localization/StringsConvertor/input/fr.lproj/app.json index fc8fd0e7a..1d998ba77 100644 --- a/Localization/StringsConvertor/input/fr.lproj/app.json +++ b/Localization/StringsConvertor/input/fr.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Vider le cache", "message": "Cache de %s effacé avec succès." + }, + "translation_failed": { + "title": "Note", + "message": "La traduction a échoué. Peut-être que l'administrateur n'a pas activé les traductions sur ce serveur ou que ce serveur utilise une ancienne version de Mastodon où les traductions ne sont pas encore prises en charge.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Créer un compte", "see_more": "Voir plus", "preview": "Aperçu", + "copy": "Copier", "share": "Partager", "share_user": "Partager %s", "share_post": "Partager la publication", @@ -91,12 +97,16 @@ "block_domain": "Bloquer %s", "unblock_domain": "Débloquer %s", "settings": "Paramètres", - "delete": "Supprimer" + "delete": "Supprimer", + "translate_post": { + "title": "Traduit depuis %s", + "unknown_language": "Inconnu" + } }, "tabs": { "home": "Accueil", - "search": "Rechercher", - "notification": "Notification", + "search_and_explore": "Rechercher et explorer", + "notifications": "Notifications", "profile": "Profil" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Contenu sensible", "media_content_warning": "Tapotez n’importe où pour révéler la publication", "tap_to_reveal": "Appuyer pour afficher", + "load_embed": "Charger l'intégration", + "link_via_user": "%s via %s", "poll": { "vote": "Voter", "closed": "Fermé" @@ -153,6 +165,7 @@ "show_image": "Afficher l’image", "show_gif": "Afficher le GIF", "show_video_player": "Afficher le lecteur vidéo", + "share_link_in_post": "Partager le lien dans le message", "tap_then_hold_to_show_menu": "Appuyez et maintenez pour afficher le menu" }, "tag": { @@ -168,6 +181,12 @@ "private": "Seul·e·s leurs abonné·e·s peuvent voir ce message.", "private_from_me": "Seul·e·s mes abonné·e·s peuvent voir ce message.", "direct": "Seul·e l’utilisateur·rice mentionnée peut voir ce message." + }, + "translation": { + "translated_from": "Traduit de %s en utilisant %s", + "unknown_language": "Inconnu", + "unknown_provider": "Inconnu", + "show_original": "Afficher l’original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Vous suit" }, "dashboard": { - "posts": "publications", - "following": "abonnements", - "followers": "abonnés" + "my_posts": "messages", + "my_following": "abonnement", + "my_followers": "abonnés", + "other_posts": "publications", + "other_following": "abonnement", + "other_followers": "abonnés" }, "fields": { + "joined": "Ici depuis", "add_row": "Ajouter une rangée", "placeholder": { "label": "Étiquette", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Favoris" + }, + "followed_tags": { + "title": "Tags suivis", + "header": { + "posts": "messages", + "participants": "participants", + "posts_today": "messages aujourd'hui" + }, + "actions": { + "follow": "Suivre", + "unfollow": "Ne plus suivre" + } } } } diff --git a/Localization/StringsConvertor/input/gd.lproj/app.json b/Localization/StringsConvertor/input/gd.lproj/app.json index 74666cb0c..5f27b8f00 100644 --- a/Localization/StringsConvertor/input/gd.lproj/app.json +++ b/Localization/StringsConvertor/input/gd.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Falamhaich an tasgadan", "message": "Chaidh %s a thasgadan fhalamhachadh." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Cruthaich cunntas", "see_more": "Seall a bharrachd", "preview": "Ro-sheall", + "copy": "Copy", "share": "Co-roinn", "share_user": "Co-roinn %s", "share_post": "Co-roinn am post", @@ -91,12 +97,16 @@ "block_domain": "Bac %s", "unblock_domain": "Dì-bhac %s", "settings": "Roghainnean", - "delete": "Sguab às" + "delete": "Sguab às", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Dachaigh", - "search": "Lorg", - "notification": "Brath", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Pròifil" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Susbaint fhrionasach", "media_content_warning": "Thoir gnogag àite sam bith gus a nochdadh", "tap_to_reveal": "Thoir gnogag gus a nochdadh", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Cuir bhòt", "closed": "Dùinte" @@ -153,6 +165,7 @@ "show_image": "Seall an dealbh", "show_gif": "Seall an GIF", "show_video_player": "Seall cluicheadair video", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Thoir gnogag ’s cùm sìos a shealltainn a’ chlàir-thaice" }, "tag": { @@ -168,6 +181,12 @@ "private": "Chan fhaic ach an luchd-leantainn aca am post seo.", "private_from_me": "Chan fhaic ach an luchd-leantainn agam am post seo.", "direct": "Chan fhaic ach an cleachdaiche air an dugadh iomradh am post seo." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "’Gad leantainn" }, "dashboard": { - "posts": "postaichean", - "following": "a’ leantainn", - "followers": "luchd-leantainn" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Cuir ràgh ris", "placeholder": { "label": "Leubail", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Comharran-lìn" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/gl.lproj/app.json b/Localization/StringsConvertor/input/gl.lproj/app.json index 15c7a612a..f8bda509e 100644 --- a/Localization/StringsConvertor/input/gl.lproj/app.json +++ b/Localization/StringsConvertor/input/gl.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Limpar caché", "message": "Baleirouse %s da caché correctamente." + }, + "translation_failed": { + "title": "Nota", + "message": "Fallou a tradución. É posible que a administración non activase a tradución neste servidor ou que o servidor teña unha versión antiga de Mastodon que non ten soporte para a tradución.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Crear conta", "see_more": "Ver máis", "preview": "Vista previa", + "copy": "Copiar", "share": "Compartir", "share_user": "Compartir %s", "share_post": "Compartir publicación", @@ -91,12 +97,16 @@ "block_domain": "Bloquear a %s", "unblock_domain": "Desbloquear a %s", "settings": "Axustes", - "delete": "Eliminar" + "delete": "Eliminar", + "translate_post": { + "title": "Traducido do %s", + "unknown_language": "Descoñecido" + } }, "tabs": { "home": "Inicio", - "search": "Busca", - "notification": "Notificación", + "search_and_explore": "Buscar e Explorar", + "notifications": "Notificacións", "profile": "Perfil" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Contido sensible", "media_content_warning": "Toca nalgures para mostrar", "tap_to_reveal": "Toca para mostrar", + "load_embed": "Cargar o contido", + "link_via_user": "%s vía %s", "poll": { "vote": "Votar", "closed": "Pechada" @@ -153,6 +165,7 @@ "show_image": "Mostrar a imaxe", "show_gif": "Mostrar GIF", "show_video_player": "Mostrar reprodutor de vídeo", + "share_link_in_post": "Compartir Ligazón na Publicación", "tap_then_hold_to_show_menu": "Toca e mantén preso para menú" }, "tag": { @@ -168,6 +181,12 @@ "private": "Só as seguidoras poden ver a publicación.", "private_from_me": "Só as miñas seguidoras poden ver esta publicación.", "direct": "Só a usuaria mencionada pode ver a publicación." + }, + "translation": { + "translated_from": "Traducido do %s usando %s", + "unknown_language": "Descoñecido", + "unknown_provider": "Descoñecido", + "show_original": "Mostrar o orixinal" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Séguete" }, "dashboard": { - "posts": "publicacións", - "following": "seguindo", - "followers": "seguidoras" + "my_posts": "publicacións", + "my_following": "seguindo", + "my_followers": "seguidoras", + "other_posts": "publicacións", + "other_following": "seguindo", + "other_followers": "seguidoras" }, "fields": { + "joined": "Uniuse", "add_row": "Engadir fila", "placeholder": { "label": "Etiqueta", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Marcadores" + }, + "followed_tags": { + "title": "Cancelos seguidos", + "header": { + "posts": "publicacións", + "participants": "participantes", + "posts_today": "publicacións de hoxe" + }, + "actions": { + "follow": "Seguir", + "unfollow": "Deixar de seguir" + } } } } diff --git a/Localization/StringsConvertor/input/he.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/he.lproj/Localizable.stringsdict new file mode 100644 index 000000000..63ed25f8a --- /dev/null +++ b/Localization/StringsConvertor/input/he.lproj/Localizable.stringsdict @@ -0,0 +1,581 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + התראה אחת שלא נקראה + two + שתי התראות שלא נקראו + many + %ld unread notifications + other + %ld התראות שלא נקראו + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + Input limit exceeds %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 character + two + %ld characters + many + %ld characters + other + %ld characters + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + Input limit remains %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 character + two + %ld characters + many + %ld characters + other + %ld characters + + + a11y.plural.count.characters_left + + NSStringLocalizedFormatKey + %#@character_count@ left + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 character + two + %ld characters + many + %ld characters + other + %ld characters + + + plural.count.followed_by_and_mutual + + NSStringLocalizedFormatKey + %#@names@%#@count_mutual@ + names + + one + + two + + many + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + + + count_mutual + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Followed by %1$@, and another mutual + two + Followed by %1$@, and %ld mutuals + many + Followed by %1$@, and %ld mutuals + other + Followed by %1$@, and %ld mutuals + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + post + two + posts + many + posts + other + posts + + + plural.count.media + + NSStringLocalizedFormatKey + %#@media_count@ + media_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 media + two + %ld media + many + %ld media + other + %ld media + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 post + two + %ld posts + many + %ld posts + other + %ld posts + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 favorite + two + %ld favorites + many + %ld favorites + other + %ld favorites + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reblog + two + %ld reblogs + many + %ld reblogs + other + %ld reblogs + + + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + two + %ld replies + many + %ld replies + other + %ld replies + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 vote + two + %ld votes + many + %ld votes + other + %ld votes + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 voter + two + %ld voters + many + %ld voters + other + %ld voters + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 people talking + two + %ld people talking + many + %ld people talking + other + %ld people talking + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 following + two + %ld following + many + %ld following + other + %ld following + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 follower + two + %ld followers + many + %ld followers + other + %ld followers + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 year left + two + %ld years left + many + %ld years left + other + %ld years left + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 months left + two + %ld months left + many + %ld months left + other + %ld months left + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 day left + two + %ld days left + many + %ld days left + other + %ld days left + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 hour left + two + %ld hours left + many + %ld hours left + other + %ld hours left + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 minute left + two + %ld minutes left + many + %ld minutes left + other + %ld minutes left + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 second left + two + %ld seconds left + many + %ld seconds left + other + %ld seconds left + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + לפני שנה + two + לפני שנתיים + many + %ldy ago + other + לפני %ld שנים + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + לפני חודש + two + לפני חודשיים + many + %ldM ago + other + לפני %ld חודשים + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + לפני יום + two + לפני יומיים + many + %ldd ago + other + לפני %ld ימים + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + לפני שעה + two + לפני שעתיים + many + %ldh ago + other + לפני %ld שעות + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + לפני דקה + two + לפני שתי דקות + many + %ldm ago + other + לפני %ld דקות + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + לפני שנייה + two + לפני שתי שניות + many + %lds ago + other + לפני %ld שניות + + + + diff --git a/Localization/StringsConvertor/input/he.lproj/app.json b/Localization/StringsConvertor/input/he.lproj/app.json new file mode 100644 index 000000000..6b484e301 --- /dev/null +++ b/Localization/StringsConvertor/input/he.lproj/app.json @@ -0,0 +1,762 @@ +{ + "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." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" + } + }, + "controls": { + "actions": { + "back": "Back", + "next": "הבא", + "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": "Log in", + "sign_up": "יצירת חשבון", + "see_more": "See More", + "preview": "Preview", + "copy": "Copy", + "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": "חסימת %s", + "unblock_domain": "הסרת חסימה מ־%s", + "settings": "הגדרות", + "delete": "Delete", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } + }, + "tabs": { + "home": "Home", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", + "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", + "sensitive_content": "תוכן רגיש", + "media_content_warning": "Tap anywhere to reveal", + "tap_to_reveal": "Tap to reveal", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", + "poll": { + "vote": "Vote", + "closed": "Closed" + }, + "meta_entity": { + "url": "Link: %s", + "hashtag": "Hashtag: %s", + "mention": "Show Profile: %s", + "email": "Email address: %s" + }, + "actions": { + "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", + "share_link_in_post": "Share Link in Post", + "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." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" + } + }, + "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", + "show_reblogs": "Show Reblogs", + "hide_reblogs": "Hide Reblogs" + }, + "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": "בואו נתחיל", + "log_in": "Log In" + }, + "login": { + "title": "Welcome back", + "subtitle": "Log you in on the server you created your account on.", + "server_search_field": { + "placeholder": "Enter URL or search for your server" + } + }, + "server_picker": { + "title": "Mastodon is made of users in different servers.", + "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.", + "button": { + "category": { + "all": "All", + "all_accessiblity_description": "Category: All", + "academia": "academia", + "activism": "אקטיביזם", + "food": "אוכל", + "furry": "furry", + "games": "משחקים", + "general": "כללי", + "journalism": "journalism", + "lgbt": "להט\"ב", + "regional": "regional", + "art": "אומנות", + "music": "מוזיקה", + "tech": "tech" + }, + "see_less": "See Less", + "see_more": "See More" + }, + "label": { + "language": "LANGUAGE", + "users": "USERS", + "category": "CATEGORY" + }, + "input": { + "search_servers_or_enter_url": "Search communities or enter URL" + }, + "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", + "lets_get_you_set_up_on_domain": "Let’s get you set up on %s", + "input": { + "avatar": { + "delete": "Delete" + }, + "username": { + "placeholder": "שם משתמש/ת", + "duplicate_prompt": "This username is taken." + }, + "display_name": { + "placeholder": "שם תצוגה" + }, + "email": { + "placeholder": "דוא״ל" + }, + "password": { + "placeholder": "סיסמה", + "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": "שם משתמש/ת", + "email": "דוא״ל", + "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.", + "tap_the_link_we_emailed_to_you_to_verify_your_account": "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...", + "accessibility": { + "logo_label": "Logo Button", + "logo_hint": "Tap to scroll to top and tap again to previous location" + } + } + }, + "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...", + "load_failed": "Load Failed", + "upload_failed": "Upload Failed", + "can_not_recognize_this_media_attachment": "Can not recognize this media attachment", + "attachment_too_large": "Attachment too large", + "compressing_state": "Compressing...", + "server_processing_state": "Server Processing..." + }, + "poll": { + "duration_time": "Duration: %s", + "thirty_minutes": "חצי שעה", + "one_hour": "שעה", + "six_hours": "6 שעות", + "one_day": "יום אחד", + "three_days": "3 ימים", + "seven_days": "7 ימים", + "option_number": "Option %ld", + "the_poll_is_invalid": "The poll is invalid", + "the_poll_has_empty_option": "The poll has empty option" + }, + "content_warning": { + "placeholder": "Write an accurate warning here..." + }, + "visibility": { + "public": "Public", + "unlisted": "Unlisted", + "private": "לעוקבים בלבד", + "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", + "post_options": "Post Options", + "posting_as": "Posting as %s" + }, + "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": { + "header": { + "follows_you": "Follows You" + }, + "dashboard": { + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" + }, + "fields": { + "joined": "Joined", + "add_row": "Add Row", + "placeholder": { + "label": "Label", + "content": "Content" + }, + "verified": { + "short": "Verified on %s", + "long": "Ownership of this link was checked on %s" + } + }, + "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" + }, + "confirm_show_reblogs": { + "title": "Show Reblogs", + "message": "Confirm to show reblogs" + }, + "confirm_hide_reblogs": { + "title": "Hide Reblogs", + "message": "Confirm to hide reblogs" + } + }, + "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": { + "title": "follower", + "footer": "Followers from other servers are not displayed." + }, + "following": { + "title": "following", + "footer": "Follows from other servers are not displayed." + }, + "familiarFollowers": { + "title": "Followers you familiar", + "followed_by_names": "Followed by %s" + }, + "favorited_by": { + "title": "Favorited By" + }, + "reblogged_by": { + "title": "Reblogged By" + }, + "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" + } + }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "community": "Community", + "for_you": "For You" + }, + "intro": "These are the posts gaining traction in your corner of Mastodon." + }, + "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" + }, + "follow_request": { + "accept": "Accept", + "accepted": "Accepted", + "reject": "reject", + "rejected": "Rejected" + } + }, + "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", + "step_one": { + "step_1_of_4": "Step 1 of 4", + "whats_wrong_with_this_post": "What's wrong with this post?", + "whats_wrong_with_this_account": "What's wrong with this account?", + "whats_wrong_with_this_username": "What's wrong with %s?", + "select_the_best_match": "Select the best match", + "i_dont_like_it": "I don’t like it", + "it_is_not_something_you_want_to_see": "It is not something you want to see", + "its_spam": "It’s spam", + "malicious_links_fake_engagement_or_repetetive_replies": "Malicious links, fake engagement, or repetetive replies", + "it_violates_server_rules": "It violates server rules", + "you_are_aware_that_it_breaks_specific_rules": "You are aware that it breaks specific rules", + "its_something_else": "It’s something else", + "the_issue_does_not_fit_into_other_categories": "The issue does not fit into other categories" + }, + "step_two": { + "step_2_of_4": "Step 2 of 4", + "which_rules_are_being_violated": "Which rules are being violated?", + "select_all_that_apply": "Select all that apply", + "i_just_don’t_like_it": "I just don’t like it" + }, + "step_three": { + "step_3_of_4": "Step 3 of 4", + "are_there_any_posts_that_back_up_this_report": "Are there any posts that back up this report?", + "select_all_that_apply": "Select all that apply" + }, + "step_four": { + "step_4_of_4": "Step 4 of 4", + "is_there_anything_else_we_should_know": "Is there anything else we should know?" + }, + "step_final": { + "dont_want_to_see_this": "Don’t want to see this?", + "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", + "unfollow": "Unfollow", + "unfollowed": "Unfollowed", + "unfollow_user": "Unfollow %s", + "mute_user": "Mute %s", + "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", + "block_user": "Block %s", + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.", + "while_we_review_this_you_can_take_action_against_user": "While we review this, you can take action against %s" + } + }, + "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" + }, + "bookmark": { + "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } + } + } +} diff --git a/Localization/StringsConvertor/input/he.lproj/ios-infoPlist.json b/Localization/StringsConvertor/input/he.lproj/ios-infoPlist.json new file mode 100644 index 000000000..c6db73de0 --- /dev/null +++ b/Localization/StringsConvertor/input/he.lproj/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" +} diff --git a/Localization/StringsConvertor/input/hi.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/hi.lproj/Localizable.stringsdict index eabdc3c32..788eb95fc 100644 --- a/Localization/StringsConvertor/input/hi.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/hi.lproj/Localizable.stringsdict @@ -15,7 +15,7 @@ one 1 unread notification other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds diff --git a/Localization/StringsConvertor/input/hi.lproj/app.json b/Localization/StringsConvertor/input/hi.lproj/app.json index f9414b6c0..e7ea54abb 100644 --- a/Localization/StringsConvertor/input/hi.lproj/app.json +++ b/Localization/StringsConvertor/input/hi.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Clean Cache", "message": "Successfully cleaned %s cache." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Create account", "see_more": "See More", "preview": "Preview", + "copy": "Copy", "share": "Share", "share_user": "Share %s", "share_post": "Share Post", @@ -91,12 +97,16 @@ "block_domain": "Block %s", "unblock_domain": "Unblock %s", "settings": "Settings", - "delete": "Delete" + "delete": "Delete", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Home", - "search": "Search", - "notification": "Notification", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Profile" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Sensitive Content", "media_content_warning": "Tap anywhere to reveal", "tap_to_reveal": "Tap to reveal", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Vote", "closed": "Closed" @@ -153,6 +165,7 @@ "show_image": "Show image", "show_gif": "Show GIF", "show_video_player": "Show video player", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Add Row", "placeholder": { "label": "Label", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/id.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/id.lproj/Localizable.stringsdict index 9b8aca01c..3a39c085f 100644 --- a/Localization/StringsConvertor/input/id.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/id.lproj/Localizable.stringsdict @@ -13,13 +13,13 @@ NSStringFormatValueTypeKey ld other - %ld unread notification + %ld notifikasi belum dibaca a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + Batas input melebihi %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -33,7 +33,7 @@ a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + Batas input masih tersisa %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -47,7 +47,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + tersisa %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -55,7 +55,7 @@ NSStringFormatValueTypeKey ld other - %ld characters + %ld karakter plural.count.followed_by_and_mutual @@ -78,7 +78,7 @@ NSStringFormatValueTypeKey ld other - Followed by %1$@, and %ld mutuals + Diikuti oleh %1$@, dan %ld mutual plural.count.metric_formatted.post @@ -148,7 +148,7 @@ NSStringFormatValueTypeKey ld other - %ld reblogs + Posting ulang %ld plural.count.reply @@ -162,7 +162,7 @@ NSStringFormatValueTypeKey ld other - %ld replies + %ld balasan plural.count.vote @@ -204,7 +204,7 @@ NSStringFormatValueTypeKey ld other - %ld people talking + %ld obrolan plural.count.following @@ -218,7 +218,7 @@ NSStringFormatValueTypeKey ld other - %ld following + %ld mengikuti plural.count.follower diff --git a/Localization/StringsConvertor/input/id.lproj/app.json b/Localization/StringsConvertor/input/id.lproj/app.json index 4f2050792..558dad5d1 100644 --- a/Localization/StringsConvertor/input/id.lproj/app.json +++ b/Localization/StringsConvertor/input/id.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Bersihkan Cache", "message": "Berhasil menghapus %s cache." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Buat akun", "see_more": "Lihat lebih banyak", "preview": "Pratinjau", + "copy": "Copy", "share": "Bagikan", "share_user": "Bagikan %s", "share_post": "Bagikan Postingan", @@ -91,12 +97,16 @@ "block_domain": "Blokir %s", "unblock_domain": "Berhenti memblokir %s", "settings": "Pengaturan", - "delete": "Hapus" + "delete": "Hapus", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Beranda", - "search": "Cari", - "notification": "Notifikasi", + "search_and_explore": "Search and Explore", + "notifications": "Notifikasi", "profile": "Profil" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Konten Sensitif", "media_content_warning": "Ketuk di mana saja untuk melihat", "tap_to_reveal": "Ketuk untuk mengungkap", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Pilih", "closed": "Ditutup" @@ -153,6 +165,7 @@ "show_image": "Tampilkan gambar", "show_gif": "Tampilkan GIF", "show_video_player": "Tampilkan pemutar video", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Ketuk lalu tahan untuk menampilkan menu" }, "tag": { @@ -164,10 +177,16 @@ "emoji": "Emoji" }, "visibility": { - "unlisted": "Everyone can see this post but not display in the public timeline.", + "unlisted": "Postingan ini dapat dilihat semua orang tetapi tidak ditampilkan di timeline publik.", "private": "Hanya pengikut mereka yang dapat melihat postingan ini.", "private_from_me": "Hanya pengikut saya yang dapat melihat postingan ini.", "direct": "Hanya pengguna yang disebut yang dapat melihat postingan ini." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -306,13 +325,13 @@ "blocked": "%s mengandung penyedia surel yang dilarang", "unreachable": "%s sepertinya tidak ada", "taken": "%s sudah digunakan", - "reserved": "%s is a reserved keyword", + "reserved": "%s adalah kata kunci yang dipesan", "accepted": "%s harus diterima", "blank": "%s diperlukan", "invalid": "%s tidak valid", "too_long": "%s terlalu panjang", "too_short": "%s terlalu pendek", - "inclusion": "%s is not a supported value" + "inclusion": "%s bukan nilai yang didukung" }, "special": { "username_invalid": "Nama pengguna hanya berisi angka karakter dan garis bawah", @@ -325,7 +344,7 @@ "server_rules": { "title": "Beberapa aturan dasar.", "subtitle": "Peraturan ini ditetapkan oleh admin %s.", - "prompt": "By continuing, you’re subject to the terms of service and privacy policy for %s.", + "prompt": "Dengan melanjutkan, Anda tunduk pada ketentuan layanan dan kebijakan privasi untuk %s.", "terms_of_service": "kebijakan layanan", "privacy_policy": "kebijakan privasi", "button": { @@ -335,10 +354,10 @@ "confirm_email": { "title": "Satu hal lagi.", "subtitle": "Kami baru saja mengirim sebuah surel ke %s,\nketuk tautannya untuk mengkonfirmasi akun Anda.", - "tap_the_link_we_emailed_to_you_to_verify_your_account": "Tap the link we emailed to you to verify your account", + "tap_the_link_we_emailed_to_you_to_verify_your_account": "Ketuk tautan yang kami kirimkan kepada Anda via email untuk memverifikasi akun Anda", "button": { "open_email_app": "Buka Aplikasi Surel", - "resend": "Resend" + "resend": "Kirim ulang" }, "dont_receive_email": { "title": "Periksa surel Anda", @@ -348,8 +367,8 @@ "open_email_app": { "title": "Periksa kotak masuk Anda.", "description": "Kami baru saja mengirimkan Anda sebuah surel. Periksa folder junk Anda jika Anda belum memeriksanya.", - "mail": "Mail", - "open_email_client": "Open Email Client" + "mail": "Pesan", + "open_email_client": "Buka Email Klien" } }, "home_timeline": { @@ -360,13 +379,13 @@ "published": "Dipublikasikan!", "Publishing": "Mempublikasikan postingan...", "accessibility": { - "logo_label": "Logo Button", - "logo_hint": "Tap to scroll to top and tap again to previous location" + "logo_label": "Tombol Logo", + "logo_hint": "Ketuk untuk menggulir ke atas dan ketuk lagi ke lokasi sebelumnya" } } }, "suggestion_account": { - "title": "Find People to Follow", + "title": "Temukan Orang untuk Diikuti", "follow_explain": "Ketika Anda mengikuti seseorang, Anda akan melihat postingan mereka di beranda Anda." }, "compose": { @@ -376,7 +395,7 @@ }, "media_selection": { "camera": "Ambil Foto", - "photo_library": "Photo Library", + "photo_library": "Galeri Foto", "browse": "Telusuri" }, "content_input_placeholder": "Ketik atau tempel apa yang Anda pada pikiran Anda", @@ -392,8 +411,8 @@ "upload_failed": "Gagal Mengunggah", "can_not_recognize_this_media_attachment": "Tidak dapat mengenali lampiran media ini", "attachment_too_large": "Lampiran terlalu besar", - "compressing_state": "Compressing...", - "server_processing_state": "Server Processing..." + "compressing_state": "Mengompres...", + "server_processing_state": "Server Memproses..." }, "poll": { "duration_time": "Durasi: %s", @@ -403,9 +422,9 @@ "one_day": "1 Hari", "three_days": "3 Hari", "seven_days": "7 Hari", - "option_number": "Option %ld", - "the_poll_is_invalid": "The poll is invalid", - "the_poll_has_empty_option": "The poll has empty option" + "option_number": "Opsi %ld", + "the_poll_is_invalid": "Japat tidak valid", + "the_poll_has_empty_option": "Japat memiliki opsi kosong" }, "content_warning": { "placeholder": "Tulis peringatan yang akurat di sini..." @@ -417,22 +436,22 @@ "direct": "Hanya orang yang saya sebut" }, "auto_complete": { - "space_to_add": "Space to add" + "space_to_add": "Tekan spasi untuk menambahkan" }, "accessibility": { "append_attachment": "Tambahkan Lampiran", "append_poll": "Tambahkan Japat", "remove_poll": "Hapus Japat", - "custom_emoji_picker": "Custom Emoji Picker", + "custom_emoji_picker": "Pemilih Emoji Kustom", "enable_content_warning": "Aktifkan Peringatan Konten", "disable_content_warning": "Nonaktifkan Peringatan Konten", - "post_visibility_menu": "Post Visibility Menu", - "post_options": "Post Options", - "posting_as": "Posting as %s" + "post_visibility_menu": "Menu Visibilitas Postingan", + "post_options": "Opsi Postingan", + "posting_as": "Posting sebagai %s" }, "keyboard": { - "discard_post": "Discard Post", - "publish_post": "Publish Post", + "discard_post": "Hapus Postingan", + "publish_post": "Publikasikan Postingan", "toggle_poll": "Toggle Poll", "toggle_content_warning": "Toggle Content Warning", "append_attachment_entry": "Tambahkan Lampiran - %s", @@ -441,47 +460,51 @@ }, "profile": { "header": { - "follows_you": "Follows You" + "follows_you": "Mengikutimu" }, "dashboard": { - "posts": "postingan", - "following": "mengikuti", - "followers": "pengikut" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { - "add_row": "Add Row", + "joined": "Bergabung", + "add_row": "Tambah Baris", "placeholder": { "label": "Label", "content": "Isi" }, "verified": { - "short": "Verified on %s", - "long": "Ownership of this link was checked on %s" + "short": "Verifikasi %s", + "long": "Kepemilikan tautan ini dapat dicek pada %s" } }, "segmented_control": { "posts": "Postingan", "replies": "Balasan", - "posts_and_replies": "Posts and Replies", + "posts_and_replies": "Kirim dan Balas", "media": "Media", - "about": "About" + "about": "Tentang" }, "relationship_action_alert": { "confirm_mute_user": { - "title": "Mute Account", - "message": "Confirm to mute %s" + "title": "Bisukan Akun", + "message": "Konfirmasi untuk bisukan %s" }, "confirm_unmute_user": { "title": "Berhenti Membisukan Akun", - "message": "Confirm to unmute %s" + "message": "Konfirmasi untuk membisukan %s" }, "confirm_block_user": { - "title": "Block Account", - "message": "Confirm to block %s" + "title": "Blokir Akun", + "message": "Konfirmasi memblokir %s" }, "confirm_unblock_user": { - "title": "Unblock Account", - "message": "Confirm to unblock %s" + "title": "Buka Blokir Akun", + "message": "Konfirmasi membuka blokir %s" }, "confirm_show_reblogs": { "title": "Show Reblogs", @@ -493,23 +516,23 @@ } }, "accessibility": { - "show_avatar_image": "Show avatar image", - "edit_avatar_image": "Edit avatar image", + "show_avatar_image": "Tampilkan gambar avatar", + "edit_avatar_image": "Ubah gambar avatar", "show_banner_image": "Show banner image", - "double_tap_to_open_the_list": "Double tap to open the list" + "double_tap_to_open_the_list": "Ketuk ganda untuk membuka daftar" } }, "follower": { - "title": "follower", + "title": "pengikut", "footer": "Followers from other servers are not displayed." }, "following": { - "title": "following", + "title": "mengikuti", "footer": "Follows from other servers are not displayed." }, "familiarFollowers": { "title": "Followers you familiar", - "followed_by_names": "Followed by %s" + "followed_by_names": "Diikuti oleh %s" }, "favorited_by": { "title": "Favorited By" @@ -526,9 +549,9 @@ "recommend": { "button_text": "Lihat Semua", "hash_tag": { - "title": "Trending on Mastodon", + "title": "Sedang Tren di Mastodon", "description": "Hashtags that are getting quite a bit of attention", - "people_talking": "%s people are talking" + "people_talking": "%s orang sedang membicarakan" }, "accounts": { "title": "Akun-akun yang mungkin Anda sukai", @@ -546,22 +569,22 @@ "empty_state": { "no_results": "Tidak ada hasil" }, - "recent_search": "Recent searches", + "recent_search": "Pencarian terbaru", "clear": "Hapus" } }, "discovery": { "tabs": { "posts": "Posts", - "hashtags": "Hashtags", - "news": "News", - "community": "Community", - "for_you": "For You" + "hashtags": "Tagar", + "news": "Berita", + "community": "Komunitas", + "for_you": "Untuk Anda" }, "intro": "These are the posts gaining traction in your corner of Mastodon." }, "favorite": { - "title": "Your Favorites" + "title": "Favorit Anda" }, "notification": { "title": { @@ -569,11 +592,11 @@ "Mentions": "Sebutan" }, "notification_description": { - "followed_you": "followed you", - "favorited_your_post": "favorited your post", + "followed_you": "mengikutimu", + "favorited_your_post": "menyukai postinganmu", "reblogged_your_post": "reblogged your post", - "mentioned_you": "mentioned you", - "request_to_follow_you": "request to follow you", + "mentioned_you": "menyebutmu", + "request_to_follow_you": "meminta mengikutimu", "poll_has_ended": "poll has ended" }, "keyobard": { @@ -581,10 +604,10 @@ "show_mentions": "Tampilkan Sebutan" }, "follow_request": { - "accept": "Accept", - "accepted": "Accepted", - "reject": "reject", - "rejected": "Rejected" + "accept": "Menerima", + "accepted": "Diterima", + "reject": "menolak", + "rejected": "Ditolak" } }, "thread": { @@ -601,11 +624,11 @@ "dark": "Selalu Gelap" }, "look_and_feel": { - "title": "Look and Feel", + "title": "Lihat dan Rasakan", "use_system": "Use System", - "really_dark": "Really Dark", - "sorta_dark": "Sorta Dark", - "light": "Light" + "really_dark": "Sangat Gelap", + "sorta_dark": "Agak Gelap", + "light": "Terang" }, "notifications": { "title": "Notifikasi", @@ -617,17 +640,17 @@ "anyone": "siapapun", "follower": "seorang pengikut", "follow": "siapapun yang saya ikuti", - "noone": "no one", + "noone": "tidak ada", "title": "Beritahu saya ketika" } }, "preference": { "title": "Preferensi", "true_black_dark_mode": "True black dark mode", - "disable_avatar_animation": "Disable animated avatars", - "disable_emoji_animation": "Disable animated emojis", + "disable_avatar_animation": "Nonaktifkan animasi avatar", + "disable_emoji_animation": "Nonaktifkan animasi emoji", "using_default_browser": "Use default browser to open links", - "open_links_in_mastodon": "Open links in Mastodon" + "open_links_in_mastodon": "Buka tautan di Mastodon" }, "boring_zone": { "title": "Zona Membosankan", @@ -649,79 +672,91 @@ } }, "report": { - "title_report": "Report", + "title_report": "Laporkan", "title": "Laporkan %s", "step1": "Langkah 1 dari 2", "step2": "Langkah 2 dari 2", "content1": "Apakah ada postingan lain yang ingin Anda tambahkan ke laporannya?", "content2": "Ada yang moderator harus tahu tentang laporan ini?", - "report_sent_title": "Thanks for reporting, we’ll look into this.", + "report_sent_title": "Terima kasih atas pelaporan Anda, kami akan memeriksa ini lebih lanjut.", "send": "Kirim Laporan", "skip_to_send": "Kirim tanpa komentar", "text_placeholder": "Ketik atau tempel komentar tambahan", - "reported": "REPORTED", + "reported": "DILAPORKAN", "step_one": { - "step_1_of_4": "Step 1 of 4", - "whats_wrong_with_this_post": "What's wrong with this post?", - "whats_wrong_with_this_account": "What's wrong with this account?", - "whats_wrong_with_this_username": "What's wrong with %s?", - "select_the_best_match": "Select the best match", - "i_dont_like_it": "I don’t like it", - "it_is_not_something_you_want_to_see": "It is not something you want to see", - "its_spam": "It’s spam", - "malicious_links_fake_engagement_or_repetetive_replies": "Malicious links, fake engagement, or repetetive replies", - "it_violates_server_rules": "It violates server rules", - "you_are_aware_that_it_breaks_specific_rules": "You are aware that it breaks specific rules", - "its_something_else": "It’s something else", + "step_1_of_4": "Langkah 1 dari 4", + "whats_wrong_with_this_post": "Ada yang salah dengan postingan ini?", + "whats_wrong_with_this_account": "Ada yang salah dengan akun ini?", + "whats_wrong_with_this_username": "Ada yang salah dengan %s?", + "select_the_best_match": "Pilih yang paling cocok", + "i_dont_like_it": "Saya tidak suka", + "it_is_not_something_you_want_to_see": "Ini bukan sesuatu yang Anda ingin lihat", + "its_spam": "Ini sampah", + "malicious_links_fake_engagement_or_repetetive_replies": "Tautan berbahaya, engagement palsu, atau balasan berulang", + "it_violates_server_rules": "Melanggar ketentuan server", + "you_are_aware_that_it_breaks_specific_rules": "Anda yakin bahwa ini melanggar ketentuan khusus", + "its_something_else": "Alasan lainnya", "the_issue_does_not_fit_into_other_categories": "The issue does not fit into other categories" }, "step_two": { - "step_2_of_4": "Step 2 of 4", - "which_rules_are_being_violated": "Which rules are being violated?", - "select_all_that_apply": "Select all that apply", + "step_2_of_4": "Langkah 2 dari 4", + "which_rules_are_being_violated": "Ketentuan manakah yang dilanggar?", + "select_all_that_apply": "Pilih semua yang berlaku", "i_just_don’t_like_it": "I just don’t like it" }, "step_three": { - "step_3_of_4": "Step 3 of 4", + "step_3_of_4": "Langkah 3 dari 4", "are_there_any_posts_that_back_up_this_report": "Are there any posts that back up this report?", - "select_all_that_apply": "Select all that apply" + "select_all_that_apply": "Pilih semua yang berlaku" }, "step_four": { - "step_4_of_4": "Step 4 of 4", - "is_there_anything_else_we_should_know": "Is there anything else we should know?" + "step_4_of_4": "Langkah 4 dari 4", + "is_there_anything_else_we_should_know": "Ada hal lain yang perlu kami ketahui?" }, "step_final": { - "dont_want_to_see_this": "Don’t want to see this?", + "dont_want_to_see_this": "Tidak ingin melihat ini?", "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", - "unfollow": "Unfollow", + "unfollow": "Berhenti ikuti", "unfollowed": "Unfollowed", - "unfollow_user": "Unfollow %s", - "mute_user": "Mute %s", + "unfollow_user": "Berhenti ikuti %s", + "mute_user": "Senyapkan %s", "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", - "block_user": "Block %s", + "block_user": "Blokir %s", "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.", "while_we_review_this_you_can_take_action_against_user": "While we review this, you can take action against %s" } }, "preview": { "keyboard": { - "close_preview": "Close Preview", - "show_next": "Show Next", - "show_previous": "Show Previous" + "close_preview": "Tutup Pratinjau", + "show_next": "Tampilkan Berikutnya", + "show_previous": "Tampilkan Sebelumnya" } }, "account_list": { - "tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher", + "tab_bar_hint": "Profil yang dipilih saat ini: %s. Ketuk dua kali kemudian tahan untuk tampilkan ikon beralih akun", "dismiss_account_switcher": "Dismiss Account Switcher", - "add_account": "Add Account" + "add_account": "Tambah Akun" }, "wizard": { - "new_in_mastodon": "New in Mastodon", + "new_in_mastodon": "Baru di Mastodon", "multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.", "accessibility_hint": "Double tap to dismiss this wizard" }, "bookmark": { - "title": "Bookmarks" + "title": "Tandai" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/id.lproj/ios-infoPlist.json b/Localization/StringsConvertor/input/id.lproj/ios-infoPlist.json index 0dde7c29e..77bf594c3 100644 --- a/Localization/StringsConvertor/input/id.lproj/ios-infoPlist.json +++ b/Localization/StringsConvertor/input/id.lproj/ios-infoPlist.json @@ -1,6 +1,6 @@ { - "NSCameraUsageDescription": "Used to take photo for post status", - "NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library", + "NSCameraUsageDescription": "Gunakan untuk mengambil foto untuk postingan status", + "NSPhotoLibraryAddUsageDescription": "Gunakan untuk menyimpan foto ke dalam Galeri Foto", "NewPostShortcutItemTitle": "Postingan Baru", "SearchShortcutItemTitle": "Cari" } diff --git a/Localization/StringsConvertor/input/is.lproj/app.json b/Localization/StringsConvertor/input/is.lproj/app.json index 191a670ed..3d01bd737 100644 --- a/Localization/StringsConvertor/input/is.lproj/app.json +++ b/Localization/StringsConvertor/input/is.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Hreinsa skyndiminni", "message": "Tókst að hreinsa %s skyndiminni." + }, + "translation_failed": { + "title": "Athugasemd", + "message": "Þýðing mistókst. Mögulega hefur kerfisstjórinn ekki virkjað þýðingar á þessum netþjóni, eða að netþjónninn sé keyrður á eldri útgáfu Mastodon þar sem þýðingar séu ekki studdar.", + "button": "Í lagi" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Stofna notandaaðgang", "see_more": "Sjá fleira", "preview": "Forskoða", + "copy": "Afrita", "share": "Deila", "share_user": "Deila %s", "share_post": "Deila færslu", @@ -91,12 +97,16 @@ "block_domain": "Útiloka %s", "unblock_domain": "Opna á %s", "settings": "Stillingar", - "delete": "Eyða" + "delete": "Eyða", + "translate_post": { + "title": "Þýða úr %s", + "unknown_language": "Óþekkt" + } }, "tabs": { "home": "Heim", - "search": "Leita", - "notification": "Tilkynning", + "search_and_explore": "Leita og kanna", + "notifications": "Tilkynningar", "profile": "Notandasnið" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Viðkvæmt efni", "media_content_warning": "Ýttu hvar sem er til að birta", "tap_to_reveal": "Ýttu til að birta", + "load_embed": "Hlaða inn ívöfnu", + "link_via_user": "%s með %s", "poll": { "vote": "Greiða atkvæði", "closed": "Lokið" @@ -153,6 +165,7 @@ "show_image": "Sýna mynd", "show_gif": "Birta GIF-myndir", "show_video_player": "Sýna myndspilara", + "share_link_in_post": "Deila tengli í færslu", "tap_then_hold_to_show_menu": "Ýttu og haltu til að sýna valmynd" }, "tag": { @@ -168,6 +181,12 @@ "private": "Einungis fylgjendur þeirra geta séð þessa færslu.", "private_from_me": "Einungis fylgjendur mínir geta séð þessa færslu.", "direct": "Einungis notendur sem minnst er á geta séð þessa færslu." + }, + "translation": { + "translated_from": "Þýtt úr %s með %s", + "unknown_language": "Óþekkt", + "unknown_provider": "Óþekkt", + "show_original": "Birta upprunalegt" } }, "friendship": { @@ -206,8 +225,8 @@ "user_blocking_warning": "Þú getur ekki séð sniðið hjá %s\nfyrr en þú hættir að útiloka hann.\nSniðið þitt lítur svona út hjá honum.", "blocked_warning": "Þú getur ekki séð sniðið hjá þessum notanda\nfyrr en hann hættir að útiloka þig.", "user_blocked_warning": "Þú getur ekki séð sniðið hjá %s\nfyrr en hann hættir að útiloka þig.", - "suspended_warning": "Þessi notandi hefur verið settur í bið.", - "user_suspended_warning": "Notandaaðgangurinn %s hefur verið settur í bið." + "suspended_warning": "Þessi notandi hefur verið settur í frysti.", + "user_suspended_warning": "Notandaaðgangurinn %s hefur verið settur í frysti." } } } @@ -444,11 +463,15 @@ "follows_you": "Fylgist með þér" }, "dashboard": { - "posts": "færslur", - "following": "fylgist með", - "followers": "fylgjendur" + "my_posts": "færslur", + "my_following": "er fylgst með", + "my_followers": "fylgjendur", + "other_posts": "færslur", + "other_following": "er fylgst með", + "other_followers": "fylgjendur" }, "fields": { + "joined": "Gerðist þátttakandi", "add_row": "Bæta við röð", "placeholder": { "label": "Skýring", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bókamerki" + }, + "followed_tags": { + "title": "Myllumerki sem fylgst er með", + "header": { + "posts": "færslur", + "participants": "þátttakendur", + "posts_today": "færslur í dag" + }, + "actions": { + "follow": "Fylgjast með", + "unfollow": "Hætta að fylgjast með" + } } } } diff --git a/Localization/StringsConvertor/input/it.lproj/app.json b/Localization/StringsConvertor/input/it.lproj/app.json index f4f21762b..d355a4c10 100644 --- a/Localization/StringsConvertor/input/it.lproj/app.json +++ b/Localization/StringsConvertor/input/it.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Pulisci la cache", "message": "Cache %s pulita con successo." + }, + "translation_failed": { + "title": "Nota", + "message": "Traduzione fallita. Forse l'amministratore non ha abilitato le traduzioni su questo server o questo server sta eseguendo una versione precedente di Mastodon in cui le traduzioni non sono ancora supportate.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Crea un account", "see_more": "Visualizza altro", "preview": "Anteprima", + "copy": "Copia", "share": "Condividi", "share_user": "Condividi %s", "share_post": "Condividi il post", @@ -91,12 +97,16 @@ "block_domain": "Blocca %s", "unblock_domain": "Sblocca %s", "settings": "Impostazioni", - "delete": "Elimina" + "delete": "Elimina", + "translate_post": { + "title": "Traduci da %s", + "unknown_language": "Sconosciuto" + } }, "tabs": { "home": "Inizio", - "search": "Cerca", - "notification": "Notifiche", + "search_and_explore": "Cerca ed Esplora", + "notifications": "Notifiche", "profile": "Profilo" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Contenuto sensibile", "media_content_warning": "Tocca ovunque per rivelare", "tap_to_reveal": "Tocca per rivelare", + "load_embed": "Carica Incorpora", + "link_via_user": "%s tramite %s", "poll": { "vote": "Vota", "closed": "Chiuso" @@ -153,13 +165,14 @@ "show_image": "Mostra immagine", "show_gif": "Mostra GIF", "show_video_player": "Mostra lettore video", + "share_link_in_post": "Condividi il collegamento nel post", "tap_then_hold_to_show_menu": "Tocca quindi tieni premuto per mostrare il menu" }, "tag": { "url": "URL", "mention": "Menzione", "link": "Collegamento", - "hashtag": "Etichetta", + "hashtag": "Hashtag", "email": "Email", "emoji": "Emoji" }, @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "Tradotto da %s utilizzando %s", + "unknown_language": "Sconosciuto", + "unknown_provider": "Sconosciuto", + "show_original": "Mostra l'originale" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Ti segue" }, "dashboard": { - "posts": "post", - "following": "seguendo", - "followers": "seguaci" + "my_posts": "post", + "my_following": "seguendo", + "my_followers": "seguaci", + "other_posts": "post", + "other_following": "seguendo", + "other_followers": "seguaci" }, "fields": { + "joined": "Profilo iscritto", "add_row": "Aggiungi riga", "placeholder": { "label": "Etichetta", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Segnalibri" + }, + "followed_tags": { + "title": "Etichette seguite", + "header": { + "posts": "post", + "participants": "partecipanti", + "posts_today": "post di oggi" + }, + "actions": { + "follow": "Segui", + "unfollow": "Smetti di seguire" + } } } } diff --git a/Localization/StringsConvertor/input/ja.lproj/app.json b/Localization/StringsConvertor/input/ja.lproj/app.json index f73faabd4..c16f12dcf 100644 --- a/Localization/StringsConvertor/input/ja.lproj/app.json +++ b/Localization/StringsConvertor/input/ja.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "キャッシュを消去", "message": "%sのキャッシュを消去しました。" + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -72,12 +77,13 @@ "discard": "破棄", "try_again": "再実行", "take_photo": "写真を撮る", - "save_photo": "写真を撮る", + "save_photo": "写真を保存", "copy_photo": "写真をコピー", - "sign_in": "Log in", - "sign_up": "Create account", + "sign_in": "ログイン", + "sign_up": "アカウント作成", "see_more": "もっと見る", "preview": "プレビュー", + "copy": "Copy", "share": "共有", "share_user": "%sを共有", "share_post": "投稿を共有", @@ -91,12 +97,16 @@ "block_domain": "%sをブロック", "unblock_domain": "%sのブロックを解除", "settings": "設定", - "delete": "削除" + "delete": "削除", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "ホーム", - "search": "検索", - "notification": "通知", + "search_and_explore": "Search and Explore", + "notifications": "通知", "profile": "プロフィール" }, "keyboard": { @@ -132,15 +142,17 @@ "sensitive_content": "閲覧注意", "media_content_warning": "どこかをタップして表示", "tap_to_reveal": "タップして表示", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "投票", "closed": "終了" }, "meta_entity": { - "url": "Link: %s", - "hashtag": "Hashtag: %s", - "mention": "Show Profile: %s", - "email": "Email address: %s" + "url": "リンク: %s", + "hashtag": "ハッシュタグ: %s", + "mention": "プロフィールを表示: %s", + "email": "メールアドレス: %s" }, "actions": { "reply": "返信", @@ -153,6 +165,7 @@ "show_image": "画像を表示", "show_gif": "GIFを表示", "show_video_player": "Show video player", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,12 @@ "private": "この投稿はフォロワーに限り見ることができます。", "private_from_me": "この投稿はフォロワーに限り見ることができます。", "direct": "この投稿はメンションされたユーザーに限り見ることができます。" + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -187,8 +206,8 @@ "unmute_user": "%sのミュートを解除", "muted": "ミュート済み", "edit_info": "編集", - "show_reblogs": "Show Reblogs", - "hide_reblogs": "Hide Reblogs" + "show_reblogs": "ブーストを表示", + "hide_reblogs": "ブーストを非表示" }, "timeline": { "filtered": "フィルター済み", @@ -220,14 +239,14 @@ }, "login": { "title": "Welcome back", - "subtitle": "Log you in on the server you created your account on.", + "subtitle": "アカウントを作成したサーバーにログインします。", "server_search_field": { - "placeholder": "Enter URL or search for your server" + "placeholder": "URLを入力またはサーバーを検索" } }, "server_picker": { "title": "サーバーを選択", - "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.", + "subtitle": "お住まいの地域、興味、目的に基づいてサーバーを選択してください。 サーバーに関係なく、Mastodonの誰とでも話せます。", "button": { "category": { "all": "すべて", @@ -254,7 +273,7 @@ "category": "カテゴリー" }, "input": { - "search_servers_or_enter_url": "Search communities or enter URL" + "search_servers_or_enter_url": "コミュニティを検索またはURLを入力" }, "empty_state": { "finding_servers": "利用可能なサーバーの検索...", @@ -335,7 +354,7 @@ "confirm_email": { "title": "さいごにもうひとつ。", "subtitle": "先程 %s にメールを送信しました。リンクをタップしてアカウントを確認してください。", - "tap_the_link_we_emailed_to_you_to_verify_your_account": "Tap the link we emailed to you to verify your account", + "tap_the_link_we_emailed_to_you_to_verify_your_account": "メールで送られたリンクへアクセスし、アカウントを認証してください", "button": { "open_email_app": "メールアプリを開く", "resend": "再送信" @@ -388,10 +407,10 @@ "attachment_broken": "%sは壊れていてMastodonにアップロードできません。", "description_photo": "閲覧が難しいユーザーへの画像説明", "description_video": "閲覧が難しいユーザーへの映像説明", - "load_failed": "Load Failed", - "upload_failed": "Upload Failed", + "load_failed": "読み込みに失敗しました", + "upload_failed": "アップロードに失敗しました", "can_not_recognize_this_media_attachment": "Can not recognize this media attachment", - "attachment_too_large": "Attachment too large", + "attachment_too_large": "添付ファイルが大きすぎます", "compressing_state": "Compressing...", "server_processing_state": "Server Processing..." }, @@ -420,14 +439,14 @@ "space_to_add": "スペースを追加" }, "accessibility": { - "append_attachment": "アタッチメントの追加", + "append_attachment": "添付ファイルを追加", "append_poll": "投票を追加", "remove_poll": "投票を消去", "custom_emoji_picker": "カスタム絵文字ピッカー", "enable_content_warning": "閲覧注意を有効にする", "disable_content_warning": "閲覧注意を無効にする", "post_visibility_menu": "投稿の表示メニュー", - "post_options": "Post Options", + "post_options": "投稿オプション", "posting_as": "Posting as %s" }, "keyboard": { @@ -435,7 +454,7 @@ "publish_post": "投稿する", "toggle_poll": "投票を切り替える", "toggle_content_warning": "閲覧注意を切り替える", - "append_attachment_entry": "アタッチメントを追加 - %s", + "append_attachment_entry": "添付ファイルを追加 - %s", "select_visibility_entry": "公開設定を選択 - %s" } }, @@ -444,11 +463,15 @@ "follows_you": "フォローされています" }, "dashboard": { - "posts": "投稿", - "following": "フォロー", - "followers": "フォロワー" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "行追加", "placeholder": { "label": "ラベル", @@ -484,12 +507,12 @@ "message": "%sのブロックを解除しますか?" }, "confirm_show_reblogs": { - "title": "Show Reblogs", - "message": "Confirm to show reblogs" + "title": "ブーストを表示", + "message": "ブーストを表示しますか?" }, "confirm_hide_reblogs": { - "title": "Hide Reblogs", - "message": "Confirm to hide reblogs" + "title": "ブーストを非表示", + "message": "ブーストを非表示にしますか?" } }, "accessibility": { @@ -512,10 +535,10 @@ "followed_by_names": "Followed by %s" }, "favorited_by": { - "title": "Favorited By" + "title": "お気に入り" }, "reblogged_by": { - "title": "Reblogged By" + "title": "ブースト" }, "search": { "title": "検索", @@ -678,28 +701,28 @@ "step_two": { "step_2_of_4": "ステップ 2/4", "which_rules_are_being_violated": "どのルールに違反していますか?", - "select_all_that_apply": "Select all that apply", - "i_just_don’t_like_it": "I just don’t like it" + "select_all_that_apply": "当てはまるものをすべて選んでください", + "i_just_don’t_like_it": "興味がありません" }, "step_three": { "step_3_of_4": "ステップ 3/4", - "are_there_any_posts_that_back_up_this_report": "Are there any posts that back up this report?", - "select_all_that_apply": "Select all that apply" + "are_there_any_posts_that_back_up_this_report": "この通報を裏付けるような投稿はありますか?", + "select_all_that_apply": "当てはまるものをすべて選んでください" }, "step_four": { "step_4_of_4": "ステップ 4/4", "is_there_anything_else_we_should_know": "その他に私たちに伝えておくべき事はありますか?" }, "step_final": { - "dont_want_to_see_this": "Don’t want to see this?", - "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", + "dont_want_to_see_this": "見えないようにしたいですか?", + "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "Mastodonで気に入らないものを見た場合、その人をあなたの体験から取り除くことができます。", "unfollow": "フォロー解除", "unfollowed": "フォロー解除しました", "unfollow_user": "%sをフォロー解除", "mute_user": "%sをミュート", - "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", + "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "ホームに投稿やブーストは表示されなくなります。相手にミュートしたことは伝わりません。", "block_user": "%sをブロック", - "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.", + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "相手はあなたの投稿を見たり、フォローしたりできなくなります。あなたにブロックされていることはわかります。", "while_we_review_this_you_can_take_action_against_user": "私たちが確認している間でも、あなたは%sさんに対して対応することができます。" } }, @@ -721,7 +744,19 @@ "accessibility_hint": "チュートリアルを閉じるには、ダブルタップしてください" }, "bookmark": { - "title": "Bookmarks" + "title": "ブックマーク" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/kab.lproj/app.json b/Localization/StringsConvertor/input/kab.lproj/app.json index 62cea8780..720f979cb 100644 --- a/Localization/StringsConvertor/input/kab.lproj/app.json +++ b/Localization/StringsConvertor/input/kab.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Sfeḍ tuffirt", "message": "Yettwasfeḍ %s n tkatut tuffirt akken iwata." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Snulfu-d amiḍan", "see_more": "Wali ugar", "preview": "Taskant", + "copy": "Copy", "share": "Bḍu", "share_user": "Bḍu %s", "share_post": "Bḍu tasuffeɣt", @@ -91,12 +97,16 @@ "block_domain": "Sewḥel %s", "unblock_domain": "Serreḥ i %s", "settings": "Iɣewwaṛen", - "delete": "Kkes" + "delete": "Kkes", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Agejdan", - "search": "Nadi", - "notification": "Tilɣa", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Amaɣnu" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Agbur amḥulfu", "media_content_warning": "Sit anida tebɣiḍ i wakken ad twaliḍ", "tap_to_reveal": "Sit i uskan", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Dɣeṛ", "closed": "Ifukk" @@ -153,6 +165,7 @@ "show_image": "Sken tugna", "show_gif": "Sken GIF", "show_video_player": "Sken ameɣri n tvidyut", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Sit teǧǧeḍ aḍad-ik•im i wakken ad d-iffeɣ wumuɣ" }, "tag": { @@ -168,6 +181,12 @@ "private": "D ineḍfaren-is kan i izemren ad walin tsuffeɣ-a.", "private_from_me": "D ineḍfaren-is kan i izemren ad walin tsuffeɣ-a.", "direct": "D ineḍfaren-is kan i izemren ad walin tsuffeɣ-a." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Yeṭṭafaṛ-ik•im" }, "dashboard": { - "posts": "tisuffaɣ", - "following": "iṭafaṛ", - "followers": "imeḍfaren" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Rnu izirig", "placeholder": { "label": "Tabzimt", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/kmr.lproj/app.json b/Localization/StringsConvertor/input/kmr.lproj/app.json index eb553885c..5e23f74b9 100644 --- a/Localization/StringsConvertor/input/kmr.lproj/app.json +++ b/Localization/StringsConvertor/input/kmr.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Pêşbîrê pak bike", "message": "Pêşbîra %s biserketî hate pakkirin." + }, + "translation_failed": { + "title": "Nîşe", + "message": "Werger têk çû. Dibe ku rêvebir werger li ser vê rajakarê çalak nekiribe an jî ev rajakar guhertoyek kevntir a Mastodon e ku werger hîn nehatiye piştgirîkirin.", + "button": "BAŞ E" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Ajimêr biafirîne", "see_more": "Bêtir bibîne", "preview": "Pêşdîtin", + "copy": "Jê bigire", "share": "Parve bike", "share_user": "%s parve bike", "share_post": "Şandiyê parve bike", @@ -91,12 +97,16 @@ "block_domain": "%s asteng bike", "unblock_domain": "%s asteng neke", "settings": "Sazkarî", - "delete": "Jê bibe" + "delete": "Jê bibe", + "translate_post": { + "title": "Ji %s wergerîne", + "unknown_language": "Nenas" + } }, "tabs": { "home": "Serrûpel", - "search": "Bigere", - "notification": "Agahdarî", + "search_and_explore": "Bigere û vekole", + "notifications": "Agahdarî", "profile": "Profîl" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Naveroka hestiyarî", "media_content_warning": "Ji bo eşkerekirinê li derekî bitikîne", "tap_to_reveal": "Ji bo dîtinê bitikîne", + "load_embed": "Load Embed", + "link_via_user": "%s bi riya %s", "poll": { "vote": "Deng bide", "closed": "Girtî" @@ -153,6 +165,7 @@ "show_image": "Wêneyê nîşan bide", "show_gif": "GIF nîşan bide", "show_video_player": "Lêdera vîdyoyê nîşan bide", + "share_link_in_post": "Girêdanê di şandiyê de parve bike", "tap_then_hold_to_show_menu": "Ji bo nîşandana menuyê dirêj bitikîne" }, "tag": { @@ -168,6 +181,12 @@ "private": "Tenê şopînerên wan dikarin vê şandiyê bibînin.", "private_from_me": "Tenê şopînerên min dikarin vê şandiyê bibînin.", "direct": "Tenê bikarhênerê qalkirî dikare vê şandiyê bibîne." + }, + "translation": { + "translated_from": "Hate wergerandin ji %s bi riya %s", + "unknown_language": "Nenas", + "unknown_provider": "Nenas", + "show_original": "A resen nîşan bide" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Te dişopîne" }, "dashboard": { - "posts": "şandî", - "following": "dişopîne", - "followers": "şopîner" + "my_posts": "şandî", + "my_following": "dişopîne", + "my_followers": "şopîner", + "other_posts": "şandî", + "other_following": "dişopîne", + "other_followers": "şopîner" }, "fields": { + "joined": "Dîroka tevlîbûnê", "add_row": "Rêzê tevlî bike", "placeholder": { "label": "Nîşan", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Şûnpel" + }, + "followed_tags": { + "title": "Hashtagên şopandî", + "header": { + "posts": "şandî", + "participants": "beşdar", + "posts_today": "şandiyên îro" + }, + "actions": { + "follow": "Bişopîne", + "unfollow": "Neşopîne" + } } } } diff --git a/Localization/StringsConvertor/input/ko.lproj/app.json b/Localization/StringsConvertor/input/ko.lproj/app.json index 070386bf9..7d4e48e09 100644 --- a/Localization/StringsConvertor/input/ko.lproj/app.json +++ b/Localization/StringsConvertor/input/ko.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "캐시 삭제", "message": "Successfully cleaned %s cache." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "확인" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "계정 생성", "see_more": "더 보기", "preview": "미리보기", + "copy": "Copy", "share": "공유", "share_user": "%s를 공유", "share_post": "게시물 공유", @@ -91,12 +97,16 @@ "block_domain": "%s 차단하기", "unblock_domain": "%s 차단 해제", "settings": "설정", - "delete": "삭제" + "delete": "삭제", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "홈", - "search": "검색", - "notification": "알림", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "프로필" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "민감한 콘텐츠", "media_content_warning": "아무 곳이나 눌러서 보기", "tap_to_reveal": "눌러서 확인", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "투표", "closed": "마감" @@ -153,6 +165,7 @@ "show_image": "이미지 표시", "show_gif": "GIF 보기", "show_video_player": "비디오 플레이어 보기", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "%s에서 %s를 사용해 번역됨", + "unknown_language": "알 수 없음", + "unknown_provider": "알 수 없음", + "show_original": "원본 보기" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "게시물", - "following": "팔로잉", - "followers": "팔로워" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "가입일", "add_row": "행 추가", "placeholder": { "label": "라벨", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "팔로우한 태그", + "header": { + "posts": "게시물", + "participants": "참가자", + "posts_today": "오늘" + }, + "actions": { + "follow": "팔로우", + "unfollow": "팔로우 해제" + } } } } diff --git a/Localization/StringsConvertor/input/lv.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/lv.lproj/Localizable.stringsdict index ac30b4f8b..fd327d745 100644 --- a/Localization/StringsConvertor/input/lv.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/lv.lproj/Localizable.stringsdict @@ -13,17 +13,17 @@ NSStringFormatValueTypeKey ld zero - %ld unread notification + %ld nelasītu paziņojumu one - 1 unread notification + 1 nelasīts paziņojums other - %ld unread notification + %ld nelasīti paziņojumi a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + Ievades ierobežojums pārsniedz %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -31,17 +31,17 @@ NSStringFormatValueTypeKey ld zero - %ld characters + %ld rakstzīmju one - 1 character + 1 rakstzīme other - %ld characters + %ld rakstzīmes a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + Ievades ierobežojums paliek %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -49,17 +49,17 @@ NSStringFormatValueTypeKey ld zero - %ld characters + %ld rakstzīmju one - 1 character + 1 rakstzīme other - %ld characters + %ld rakstzīmes a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + %#@character_count@ palikušas character_count NSStringFormatSpecTypeKey @@ -67,11 +67,11 @@ NSStringFormatValueTypeKey ld zero - %ld characters + %ld rakstzīmju one - 1 character + 1 rakstzīme other - %ld characters + %ld rakstzīmes plural.count.followed_by_and_mutual @@ -98,11 +98,11 @@ NSStringFormatValueTypeKey ld zero - Followed by %1$@, and %ld mutuals + Seko %1$@ un %ld kopīgi one - Followed by %1$@, and another mutual + Seko %1$@ un vēl viens kopīgs other - Followed by %1$@, and %ld mutuals + Seko %1$@ un %ld kopīgi plural.count.metric_formatted.post @@ -116,11 +116,11 @@ NSStringFormatValueTypeKey ld zero - posts + ziņu one - post + ziņa other - posts + ziņas plural.count.media @@ -134,11 +134,11 @@ NSStringFormatValueTypeKey ld zero - %ld media + %ld multivide one - 1 media + 1 multivide other - %ld media + %ld multivide plural.count.post @@ -152,11 +152,11 @@ NSStringFormatValueTypeKey ld zero - %ld posts + %ld ziņu one - 1 post + 1 ziņa other - %ld posts + %ld ziņas plural.count.favorite @@ -170,11 +170,11 @@ NSStringFormatValueTypeKey ld zero - %ld favorites + %ld iecienītu one - 1 favorite + 1 iecienīts other - %ld favorites + %ld iecienīti plural.count.reblog @@ -188,11 +188,11 @@ NSStringFormatValueTypeKey ld zero - %ld reblogs + %ld reblogu one - 1 reblog + 1 reblogs other - %ld reblogs + %ld reblogi plural.count.reply @@ -206,11 +206,11 @@ NSStringFormatValueTypeKey ld zero - %ld replies + %ld atbilžu one - 1 reply + 1 atbilde other - %ld replies + %ld atbildes plural.count.vote @@ -224,11 +224,11 @@ NSStringFormatValueTypeKey ld zero - %ld votes + %ld balsu one - 1 vote + 1 balss other - %ld votes + %ld balsis plural.count.voter @@ -242,11 +242,11 @@ NSStringFormatValueTypeKey ld zero - %ld voters + %ld balsotāju one - 1 voter + 1 balsotājs other - %ld voters + %ld balsotāji plural.people_talking @@ -260,11 +260,11 @@ NSStringFormatValueTypeKey ld zero - %ld people talking + %ld cilvēku apspriež one - 1 people talking + 1 cilvēks apspriež other - %ld people talking + %ld cilvēki apspriež plural.count.following @@ -278,11 +278,11 @@ NSStringFormatValueTypeKey ld zero - %ld following + %ld sekotāju one - 1 following + 1 sekotājs other - %ld following + %ld sekotāji plural.count.follower @@ -296,11 +296,11 @@ NSStringFormatValueTypeKey ld zero - %ld followers + %ld sekotāju one - 1 follower + 1 sekotājs other - %ld followers + %ld sekotāji date.year.left @@ -314,11 +314,11 @@ NSStringFormatValueTypeKey ld zero - %ld years left + palicis %ld gadu one - 1 year left + palicis 1 gads other - %ld years left + palikuši %ld gadi date.month.left @@ -332,11 +332,11 @@ NSStringFormatValueTypeKey ld zero - %ld months left + palicis %ld mēnešu one - 1 months left + palicis 1 mēnesis other - %ld months left + palikuši %ld mēneši date.day.left @@ -350,11 +350,11 @@ NSStringFormatValueTypeKey ld zero - %ld days left + palikušas %ld dienas one - 1 day left + palikusi 1 diena other - %ld days left + palikušas %ld dienas date.hour.left @@ -368,11 +368,11 @@ NSStringFormatValueTypeKey ld zero - %ld hours left + atlikušas %ld stundas one - 1 hour left + atlikusi 1 stunda other - %ld hours left + atlikušas %ld stundas date.minute.left @@ -386,11 +386,11 @@ NSStringFormatValueTypeKey ld zero - %ld minutes left + atlikušas %ld minūtes one - 1 minute left + atlikusi 1 minūte other - %ld minutes left + atlikušas %ld minūtes date.second.left @@ -404,11 +404,11 @@ NSStringFormatValueTypeKey ld zero - %ld seconds left + atlikušas %ld sekundes one - 1 second left + atlikusi 1 sekunde other - %ld seconds left + atlikušas %ld sekundes date.year.ago.abbr @@ -422,11 +422,11 @@ NSStringFormatValueTypeKey ld zero - %ldy ago + pirms %ld g. one - 1y ago + pirms 1 g. other - %ldy ago + pirms %ld g. date.month.ago.abbr @@ -440,11 +440,11 @@ NSStringFormatValueTypeKey ld zero - %ldM ago + pirms %ld M. one - 1M ago + pirms 1 M. other - %ldM ago + pirms %ld M. date.day.ago.abbr @@ -458,11 +458,11 @@ NSStringFormatValueTypeKey ld zero - %ldd ago + pirms %ld d. one - 1d ago + pirms 1 d. other - %ldd ago + pirms %ld d. date.hour.ago.abbr @@ -476,11 +476,11 @@ NSStringFormatValueTypeKey ld zero - %ldh ago + pirms %ld st. one - 1h ago + pirms 1 st. other - %ldh ago + pirms %ld st. date.minute.ago.abbr @@ -494,11 +494,11 @@ NSStringFormatValueTypeKey ld zero - %ldm ago + pirms %ld m. one - 1m ago + pirms 1 m. other - %ldm ago + pirms %ld m. date.second.ago.abbr @@ -512,11 +512,11 @@ NSStringFormatValueTypeKey ld zero - %lds ago + pirms %ld s. one - 1s ago + pirms 1 s. other - %lds ago + pirms %ld s. diff --git a/Localization/StringsConvertor/input/lv.lproj/app.json b/Localization/StringsConvertor/input/lv.lproj/app.json index 1ca18400b..01a8d0515 100644 --- a/Localization/StringsConvertor/input/lv.lproj/app.json +++ b/Localization/StringsConvertor/input/lv.lproj/app.json @@ -6,30 +6,30 @@ "please_try_again_later": "Lūdzu, mēģiniet vēlreiz vēlāk." }, "sign_up_failure": { - "title": "Sign Up Failure" + "title": "Reģistrācijas Neveiksme" }, "server_error": { "title": "Servera kļūda" }, "vote_failure": { - "title": "Vote Failure", + "title": "Balsošanas Neveiksme", "poll_ended": "Balsošana beidzās" }, "discard_post_content": { "title": "Atmest malnrakstu", - "message": "Confirm to discard composed post content." + "message": "Apstiprini, lai atmestu izveidotās ziņas saturu." }, "publish_post_failure": { - "title": "Publish Failure", - "message": "Failed to publish the post.\nPlease check your internet connection.", + "title": "Publicēšanas Neveiksme", + "message": "Neizdevās publicēt ziņu.\nLūdzu, pārbaudi savu interneta savienojumu.", "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": "Nevar pievienot videoklipu ziņai, kurā jau ir attēli.", + "more_than_one_video": "Nevar pievienot vairāk kā vienu video." } }, "edit_profile_failure": { - "title": "Edit Profile Error", - "message": "Cannot edit profile. Please try again." + "title": "Profila Rediģēšanas Kļūda", + "message": "Nevar rediģēt profilu. Lūdzu mēģini vēlreiz." }, "sign_out": { "title": "Iziet", @@ -37,20 +37,25 @@ "confirm": "Iziet" }, "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": "Vai tiešām tiešām vēlies bloķēt visu %s? Vairumā gadījumu pietiek ar dažiem mērķtiecīgiem blokiem vai klusinātājiem, un tie ir vēlami. Tu neredzēsi saturu no šī domēna, un visi tavi sekotāji no šī domēna tiks noņemti.", + "block_entire_domain": "Bloķēt Domēnu" }, "save_photo_failure": { - "title": "Save Photo Failure", - "message": "Please enable the photo library access permission to save the photo." + "title": "Attēla Saglabāšanas Kļūda", + "message": "Lai saglabātu fotoattēlu, lūdzu, iespējo fotoattēlu bibliotēkas piekļuves atļauju." }, "delete_post": { "title": "Dzēst ierakstu", "message": "Vai tiešām vēlies dzēst ierakstu?" }, "clean_cache": { - "title": "Clean Cache", - "message": "Successfully cleaned %s cache." + "title": "Iztīrīt Kešatmiņu", + "message": "%s kešatmiņa ir veiksmīgi iztīrīta." + }, + "translation_failed": { + "title": "Piezīme", + "message": "Tulkošana neizdevās. Varbūt administrators nav iespējojis tulkojumus šajā serverī vai arī šajā serverī darbojas vecāka Mastodon versija, kurā tulkojumi vēl netiek atbalstīti.", + "button": "Labi" } }, "controls": { @@ -74,48 +79,53 @@ "take_photo": "Uzņemt bildi", "save_photo": "Saglabāt bildi", "copy_photo": "Kopēt bildi", - "sign_in": "Log in", - "sign_up": "Create account", + "sign_in": "Pieteikties", + "sign_up": "Izveidot kontu", "see_more": "Skatīt vairāk", "preview": "Priekšskatījums", + "copy": "Kopēt", "share": "Dalīties", - "share_user": "Share %s", - "share_post": "Share Post", + "share_user": "Kopīgot %s", + "share_post": "Kopīgot Ziņu", "open_in_safari": "Atvērt Safari", "open_in_browser": "Atvērt pārlūkprogrammā", "find_people": "Atrodi cilvēkus kam sekot", - "manually_search": "Manually search instead", + "manually_search": "Tā vietā meklēt manuāli", "skip": "Izlaist", "reply": "Atbildēt", "report_user": "Ziņot par lietotāju @%s", "block_domain": "Bloķēt %s", "unblock_domain": "Atbloķēt %s", "settings": "Iestatījumi", - "delete": "Dzēst" + "delete": "Dzēst", + "translate_post": { + "title": "Tulkot no %s", + "unknown_language": "Nezināms" + } }, "tabs": { "home": "Sākums", - "search": "Meklēšana", - "notification": "Paziņojums", + "search_and_explore": "Meklēt un Pārlūkot", + "notifications": "Paziņojumi", "profile": "Profils" }, "keyboard": { "common": { "switch_to_tab": "Pārslēgties uz: %s", "compose_new_post": "Veidot jaunu ziņu", - "show_favorites": "Show Favorites", + "show_favorites": "Parādīt Izlasi", "open_settings": "Atvērt iestatījumus" }, "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", + "previous_status": "Iepriekšējā Ziņa", + "next_status": "Nākamā Ziņa", + "open_status": "Atvērt Ziņu", + "open_author_profile": "Atvērt Autora Profilu", + "open_reblogger_profile": "Atvērt Reblogotāja Profilu", + "reply_status": "Atbildēt uz Ziņu", + "toggle_reblog": "Pārslēgt Reblogs uz Ziņu", + "toggle_favorite": "Pārslēgt Izlasi uz Ziņas", + "toggle_content_warning": "Pārslēgt Satura Brīdinājumu", "preview_image": "Priekšskata attēls" }, "segmented_control": { @@ -124,50 +134,59 @@ } }, "status": { - "user_reblogged": "%s reblogged", - "user_replied_to": "Replied to %s", - "show_post": "Show Post", + "user_reblogged": "%s reblogoja", + "user_replied_to": "Atbildēja %s", + "show_post": "Parādīt Ziņu", "show_user_profile": "Parādīt lietotāja profilu", "content_warning": "Satura brīdinājums", "sensitive_content": "Sensitīvs saturs", - "media_content_warning": "Tap anywhere to reveal", - "tap_to_reveal": "Tap to reveal", + "media_content_warning": "Pieskarieties jebkurā vietā, lai atklātu", + "tap_to_reveal": "Piest, lai atklātu", + "load_embed": "Ielādēt Iegultos", + "link_via_user": "%s caur %s", "poll": { "vote": "Balsot", "closed": "Aizvērts" }, "meta_entity": { - "url": "Link: %s", - "hashtag": "Hashtag: %s", - "mention": "Show Profile: %s", - "email": "Email address: %s" + "url": "Saite: %s", + "hashtag": "Sajaukt: %s", + "mention": "Rādīt Profilu: %s", + "email": "E-pasta adrese: %s" }, "actions": { "reply": "Atbildēt", "reblog": "Reblogot", - "unreblog": "Undo reblog", + "unreblog": "Atsaukt reblogu", "favorite": "Izlase", "unfavorite": "Izņemt no izlases", "menu": "Izvēlne", "hide": "Slēpt", "show_image": "Rādīt attēlu", "show_gif": "Rādīt GIF", - "show_video_player": "Show video player", - "tap_then_hold_to_show_menu": "Tap then hold to show menu" + "show_video_player": "Rādīt video atskaņotāju", + "share_link_in_post": "Kopīgot Saiti Ziņā", + "tap_then_hold_to_show_menu": "Pieskaries un turi, lai parādītu izvēlni" }, "tag": { "url": "URL", "mention": "Pieminēt", "link": "Saite", - "hashtag": "Hashtag", + "hashtag": "Tēmturis", "email": "E-pasts", "emoji": "Emocijzīmes" }, "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": "Ikviens var redzēt šo ziņu, bet to nevar parādīt publiskajā laikrindā.", + "private": "Šo ziņu var redzēt tikai viņu sekotāji.", + "private_from_me": "Šo ziņu var redzēt tikai mani sekotāji.", + "direct": "Šo ziņu var redzēt tikai minētais lietotājs." + }, + "translation": { + "translated_from": "Tulkots no %s, izmantojot %s", + "unknown_language": "Nezināms", + "unknown_provider": "Nezināms", + "show_original": "Parādīts Oriģināls" } }, "friendship": { @@ -186,9 +205,9 @@ "unmute": "Noņemt apklusinājumu", "unmute_user": "Noņemt apklusinājumu @%s", "muted": "Apklusināts", - "edit_info": "Edit Info", - "show_reblogs": "Show Reblogs", - "hide_reblogs": "Hide Reblogs" + "edit_info": "Rediģēt", + "show_reblogs": "Rādīt Reblogus", + "hide_reblogs": "Paslēpt Reblogus" }, "timeline": { "filtered": "Filtrēts", @@ -196,48 +215,48 @@ "now": "Tagad" }, "loader": { - "load_missing_posts": "Load missing posts", - "loading_missing_posts": "Loading missing posts...", + "load_missing_posts": "Ielādēt trūkstošās ziņas", + "loading_missing_posts": "Ielādē trūkstošās ziņas...", "show_more_replies": "Rādīt vairāk atbildes" }, "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": "Nav Atrastu Ziņu", + "blocking_warning": "Tu nevari skatīt šī lietotāja profilu,\nlīdz tu tos atbloķē.\nTavs profils viņiem izskatās šādi.", + "user_blocking_warning": "Tu nevari skatīt %s profilu,\nlīdz tu tos atbloķē.\nTavs profils viņiem izskatās šādi.", + "blocked_warning": "Tu nevari skatīt šī lietotāja profilu\nlīdz tie tevi atbloķē.", + "user_blocked_warning": "Tu nevari skatīt %s profilu,\nlīdz tie tevi atbloķē.", + "suspended_warning": "Šī lietotāja darbība ir apturēta.", + "user_suspended_warning": "%s konta darbība ir apturēta." } } } }, "scene": { "welcome": { - "slogan": "Social networking\nback in your hands.", - "get_started": "Get Started", + "slogan": "Sociālie tīkli\natpakaļ tavās rokās.", + "get_started": "Sāc", "log_in": "Pieteikties" }, "login": { - "title": "Welcome back", - "subtitle": "Log you in on the server you created your account on.", + "title": "Laipni lūdzam atpakaļ", + "subtitle": "Piesakies serverī, kurā izveidoji savu kontu.", "server_search_field": { - "placeholder": "Enter URL or search for your server" + "placeholder": "Ievadi URL vai meklē savu serveri" } }, "server_picker": { - "title": "Mastodon is made of users in different servers.", - "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.", + "title": "Mastodon veido lietotāji dažādos serveros.", + "subtitle": "Izvēlieties serveri, pamatojoties uz savu reģionu, interesēm vai vispārīgu mērķi. Tu joprojām vari tērzēt ar jebkuru Mastodon lietotāju neatkarīgi no taviem serveriem.", "button": { "category": { "all": "Visi", "all_accessiblity_description": "Katekorija: Visi", - "academia": "academia", - "activism": "activism", + "academia": "akadēmija", + "activism": "aktīvisms", "food": "ēdiens", - "furry": "furry", + "furry": "pūkains", "games": "spēles", - "general": "general", + "general": "galvenais", "journalism": "žurnālisms", "lgbt": "lgbt", "regional": "regionāli", @@ -254,17 +273,17 @@ "category": "KATEGORIJA" }, "input": { - "search_servers_or_enter_url": "Search communities or enter URL" + "search_servers_or_enter_url": "Meklēt kopienas vai ievadīt URL" }, "empty_state": { - "finding_servers": "Finding available servers...", - "bad_network": "Something went wrong while loading the data. Check your internet connection.", + "finding_servers": "Meklē piejamos serverus...", + "bad_network": "Ielādējot datus, radās problēma. Pārbaudi interneta savienojumu.", "no_results": "Nav rezultātu" } }, "register": { - "title": "Let’s get you set up on %s", - "lets_get_you_set_up_on_domain": "Let’s get you set up on %s", + "title": "Ļauj tevi iestatīt %s", + "lets_get_you_set_up_on_domain": "Ļauj tevi iestatīt %s", "input": { "avatar": { "delete": "Dzēst" @@ -281,7 +300,7 @@ }, "password": { "placeholder": "parole", - "require": "Your password needs at least:", + "require": "Tavai parolei ir nepieciešams vismaz:", "character_limit": "8 rakstzīmes", "accessibility": { "checked": "atzīmēts", @@ -303,29 +322,29 @@ "reason": "Iemesls" }, "reason": { - "blocked": "%s contains a disallowed email provider", + "blocked": "%s satur neatļautu e-pasta pakalpojumu sniedzēju", "unreachable": "%s šķiet, ka neeksistē", "taken": "%s jau tiek izmantots", - "reserved": "%s is a reserved keyword", - "accepted": "%s must be accepted", + "reserved": "%s ir rezervēts atslēgvārds", + "accepted": "%s jābūt apstiprinātām", "blank": "%s ir obligāts", "invalid": "%s ir nederīgs", "too_long": "%s ir pārāk garaš", "too_short": "%s ir pārāk īs", - "inclusion": "%s is not a supported value" + "inclusion": "%s nav atbalstīta vērtība" }, "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": "Lietotājvārdā drīkst būt tikai burtciparu rakstzīmes un zemsvītras", + "username_too_long": "Lietotājvārds ir par garu (nedrīkst būt garāks par 30 rakstzīmēm)", + "email_invalid": "Šī nav derīga e-pasta adrese", + "password_too_short": "Parole ir pārāk īsa (jābūt vismaz 8 rakstzīmēm)" } } }, "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.", + "title": "Daži pamatnoteikumi.", + "subtitle": "Tos iestata un ievieš %s moderatori.", + "prompt": "Turpinot, uz tevi attiecas %s pakalpojumu sniegšanas noteikumi un konfidencialitātes politika.", "terms_of_service": "pakalpojuma noteikumi", "privacy_policy": "privātuma nosacījumi", "button": { @@ -333,45 +352,45 @@ } }, "confirm_email": { - "title": "One last thing.", - "subtitle": "Tap the link we emailed to you to verify your account.", - "tap_the_link_we_emailed_to_you_to_verify_your_account": "Tap the link we emailed to you to verify your account", + "title": "Pēdējā lieta.", + "subtitle": "Pieskaries saitei, ko nosūtījām tev pa e-pastu, lai verificētu savu kontu.", + "tap_the_link_we_emailed_to_you_to_verify_your_account": "Pieskaries saitei, ko nosūtījām tev pa e-pastu, lai verificētu savu kontu", "button": { - "open_email_app": "Open Email App", + "open_email_app": "Atvērt E-pasta Lietotni", "resend": "Nosūtīt atkārtoti" }, "dont_receive_email": { "title": "Pārbaudi savu e-pastu", - "description": "Check if your email address is correct as well as your junk folder if you haven’t.", + "description": "Pārbaudi, vai tava e-pasta adrese ir pareiza, kā arī savu mēstuļu mapi, ja tā nav.", "resend_email": "Atkārtoti nosūtīt e-pastu" }, "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": "Pārbaudi savu iesūtni.", + "description": "Mēs tikko nosūtījām tev e-pastu. Pārbaudi savu mēstuļu mapi, ja neesi to saņēmis.", + "mail": "Pasts", + "open_email_client": "Atvērt E-pasta Klientu" } }, "home_timeline": { - "title": "Home", + "title": "Sākums", "navigation_bar_state": { - "offline": "Offline", - "new_posts": "See new posts", - "published": "Published!", - "Publishing": "Publishing post...", + "offline": "Bezsaistē", + "new_posts": "Skatīt jaunās ziņas", + "published": "Publicēts!", + "Publishing": "Publicē ziņu...", "accessibility": { - "logo_label": "Logo Button", - "logo_hint": "Tap to scroll to top and tap again to previous location" + "logo_label": "Logotipa Poga", + "logo_hint": "Pieskaries, lai ritinātu uz augšu, un vēlreiz pieskaries iepriekšējai atrašanās vietai" } } }, "suggestion_account": { - "title": "Find People to Follow", - "follow_explain": "When you follow someone, you’ll see their posts in your home feed." + "title": "Atrodi Cilvēkus kam Sekot", + "follow_explain": "Kad seko kādam, tu redzēsi viņu ziņas savā mājas plūsmā." }, "compose": { "title": { - "new_post": "New Post", + "new_post": "Jauna Ziņa", "new_reply": "Jauna atbilde" }, "media_selection": { @@ -379,36 +398,36 @@ "photo_library": "Attēlu krātuve", "browse": "Pārlūkot" }, - "content_input_placeholder": "Type or paste what’s on your mind", + "content_input_placeholder": "Ieraksti vai ielīmē to, ko domā", "compose_action": "Publicēt", - "replying_to_user": "replying to %s", + "replying_to_user": "atbildot uz %s", "attachment": { "photo": "attēls", "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...", - "load_failed": "Load Failed", - "upload_failed": "Upload Failed", - "can_not_recognize_this_media_attachment": "Can not recognize this media attachment", - "attachment_too_large": "Attachment too large", - "compressing_state": "Compressing...", - "server_processing_state": "Server Processing..." + "attachment_broken": "Šis %s ir salauzts un nevar tikt augšuplādēts Mastodon.", + "description_photo": "Apraksti fotoattēlu vājredzīgajiem...", + "description_video": "Apraksti video vājredzīgajiem...", + "load_failed": "Ielāde Neizdevās", + "upload_failed": "Augšupielāde Neizdevās", + "can_not_recognize_this_media_attachment": "Nevar atpazīt šo multivides pielikumu", + "attachment_too_large": "Pārāk liels pielikums", + "compressing_state": "Saspiež...", + "server_processing_state": "Notiek servera apstrāde..." }, "poll": { - "duration_time": "Duration: %s", + "duration_time": "Ilgums: %s", "thirty_minutes": "30 minūtes", "one_hour": "1 Stunda", "six_hours": "6 stundas", "one_day": "1 Diena", "three_days": "3 Dienas", "seven_days": "7 Dienas", - "option_number": "Option %ld", - "the_poll_is_invalid": "The poll is invalid", - "the_poll_has_empty_option": "The poll has empty option" + "option_number": "Izvēle %ld", + "the_poll_is_invalid": "Aptauja nav derīga", + "the_poll_has_empty_option": "Aptaujai ir tukša opcija" }, "content_warning": { - "placeholder": "Write an accurate warning here..." + "placeholder": "Uzraksti šeit precīzu brīdinājumu..." }, "visibility": { "public": "Publisks", @@ -417,26 +436,26 @@ "direct": "Tikai cilvēki, kurus es pieminu" }, "auto_complete": { - "space_to_add": "Space to add" + "space_to_add": "Vieta, ko pievienot" }, "accessibility": { "append_attachment": "Pievienot pielikumu", "append_poll": "Pievienot aptauju", "remove_poll": "Noņemt aptauju", - "custom_emoji_picker": "Custom Emoji Picker", - "enable_content_warning": "Enable Content Warning", - "disable_content_warning": "Disable Content Warning", - "post_visibility_menu": "Post Visibility Menu", - "post_options": "Post Options", - "posting_as": "Posting as %s" + "custom_emoji_picker": "Pielāgoto Emocijzīmju Atlasītājs", + "enable_content_warning": "Iespējot Satura Brīdinājumu", + "disable_content_warning": "Atspējot Satura Brīdinājumu", + "post_visibility_menu": "Ziņu Redzamības Izvēlne", + "post_options": "Ziņas Iespējas", + "posting_as": "Publicēt kā %s" }, "keyboard": { - "discard_post": "Discard Post", - "publish_post": "Publish Post", - "toggle_poll": "Toggle Poll", - "toggle_content_warning": "Toggle Content Warning", + "discard_post": "Izmest Ziņu", + "publish_post": "Publicēt Ziņu", + "toggle_poll": "Pārslēgt Aptauju", + "toggle_content_warning": "Pārslēgt Satura Brīdinājumu", "append_attachment_entry": "Pievienot pielikumu - %s", - "select_visibility_entry": "Select Visibility - %s" + "select_visibility_entry": "Atlasīt Redzamību — %s" } }, "profile": { @@ -444,23 +463,27 @@ "follows_you": "Seko tev" }, "dashboard": { - "posts": "posts", - "following": "seko", - "followers": "sekottāji" + "my_posts": "ziņas", + "my_following": "seko", + "my_followers": "sekotāji", + "other_posts": "ziņas", + "other_following": "seko", + "other_followers": "sekotāji" }, "fields": { + "joined": "Pievienojās", "add_row": "Pievienot rindu", "placeholder": { - "label": "Label", + "label": "Marķējums", "content": "Saturs" }, "verified": { - "short": "Verified on %s", - "long": "Ownership of this link was checked on %s" + "short": "Pārbaudīts %s", + "long": "Šīs saites piederība tika pārbaudīta %s" } }, "segmented_control": { - "posts": "Posts", + "posts": "Ziņas", "replies": "Atbildes", "posts_and_replies": "Ziņas un atbildes", "media": "Multivide", @@ -468,97 +491,97 @@ }, "relationship_action_alert": { "confirm_mute_user": { - "title": "Mute Account", - "message": "Confirm to mute %s" + "title": "Izslēgt Kontu", + "message": "Apstiprināt, lai izslēgtu %s skaņu" }, "confirm_unmute_user": { - "title": "Unmute Account", - "message": "Confirm to unmute %s" + "title": "Ieslēgt Kontu", + "message": "Apstiprināt, lai ieslēgtu %s skaņu" }, "confirm_block_user": { "title": "Bloķēts kontu", - "message": "Confirm to block %s" + "message": "Apstiprināt, lai bloķētu %s" }, "confirm_unblock_user": { "title": "Atbloķēt kontu", "message": "Apstiprini lai atbloķētu %s" }, "confirm_show_reblogs": { - "title": "Show Reblogs", - "message": "Confirm to show reblogs" + "title": "Rādīt Reblogus", + "message": "Apstiprināt, lai rādītu reblogus" }, "confirm_hide_reblogs": { - "title": "Hide Reblogs", - "message": "Confirm to hide reblogs" + "title": "Paslēpt Reblogus", + "message": "Apstiprināt, lai slēptu reblogus" } }, "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": "Rādīt avatara attēlu", + "edit_avatar_image": "Rediģēt avatara attēlu", + "show_banner_image": "Rādīt bannera attēlu", + "double_tap_to_open_the_list": "Dubultskāriens, lai atvērtu sarakstu" } }, "follower": { "title": "sekottājs", - "footer": "Followers from other servers are not displayed." + "footer": "Sekotāji no citiem serveriem netiek rādīti." }, "following": { "title": "seko", - "footer": "Follows from other servers are not displayed." + "footer": "Sekojumi no citiem serveriem netiek rādīti." }, "familiarFollowers": { - "title": "Followers you familiar", - "followed_by_names": "Followed by %s" + "title": "Tev pazīstamie sekotāji", + "followed_by_names": "Seko %s" }, "favorited_by": { - "title": "Favorited By" + "title": "Pievienoja izlasei" }, "reblogged_by": { - "title": "Reblogged By" + "title": "Reblogoja" }, "search": { "title": "Meklēt", "search_bar": { - "placeholder": "Search hashtags and users", + "placeholder": "Meklēt tēmturus un lietotājus", "cancel": "Atcelt" }, "recommend": { "button_text": "Skatīt visu", "hash_tag": { - "title": "Trending on Mastodon", - "description": "Hashtags that are getting quite a bit of attention", - "people_talking": "%s people are talking" + "title": "Tendences vietnē Mastodon", + "description": "Tēmturi, kuriem tiek pievērsta diezgan liela uzmanība", + "people_talking": "%s cilvēki apspriež" }, "accounts": { - "title": "Accounts you might like", - "description": "You may like to follow these accounts", - "follow": "Follow" + "title": "Konti, kuri tev varētu patikt", + "description": "Iespējams, tu vēlēsies sekot šiem kontiem", + "follow": "Sekot" } }, "searching": { "segment": { - "all": "All", - "people": "People", - "hashtags": "Hashtags", - "posts": "Posts" + "all": "Visi", + "people": "Cilvēki", + "hashtags": "Tēmturi", + "posts": "Ziņas" }, "empty_state": { - "no_results": "No results" + "no_results": "Nav rezultātu" }, - "recent_search": "Recent searches", - "clear": "Clear" + "recent_search": "Nesen meklētais", + "clear": "Notīrīt" } }, "discovery": { "tabs": { "posts": "Ziņas", - "hashtags": "Hashtags", + "hashtags": "Tēmturi", "news": "Ziņas", - "community": "Community", + "community": "Kopiena", "for_you": "Priekš tevis" }, - "intro": "These are the posts gaining traction in your corner of Mastodon." + "intro": "Šīs ir ziņas, kas iekaro tavu Mastodon stūrīti." }, "favorite": { "title": "Tava izlase" @@ -569,16 +592,16 @@ "Mentions": "Pieminējumi" }, "notification_description": { - "followed_you": "followed you", - "favorited_your_post": "favorited your post", - "reblogged_your_post": "reblogged your post", + "followed_you": "tev sekoja", + "favorited_your_post": "izcēla tavu ziņu", + "reblogged_your_post": "reblogoja tavu ziņu", "mentioned_you": "pieminēja tevi", - "request_to_follow_you": "request to follow you", + "request_to_follow_you": "lūgums tev sekot", "poll_has_ended": "balsošana beidzās" }, "keyobard": { "show_everything": "Parādīt man visu", - "show_mentions": "Show Mentions" + "show_mentions": "Rādīt Pieminējumus" }, "follow_request": { "accept": "Pieņemt", @@ -589,7 +612,7 @@ }, "thread": { "back_title": "Ziņa", - "title": "Post from %s" + "title": "Ziņa no %s" }, "settings": { "title": "Iestatījumi", @@ -602,42 +625,42 @@ }, "look_and_feel": { "title": "Izskats", - "use_system": "Use System", + "use_system": "Lietot Sistēmas", "really_dark": "Ļoti tumšs", "sorta_dark": "Itkā tumšs", "light": "Gaišs" }, "notifications": { "title": "Paziņojumi", - "favorites": "Favorites my post", + "favorites": "Izceļ manu ziņu", "follows": "Seko man", - "boosts": "Reblogs my post", + "boosts": "Reblogo manu ziņu", "mentions": "Pieminējumi", "trigger": { "anyone": "jebkurš", "follower": "sekottājs", - "follow": "anyone I follow", + "follow": "jebkurš, kam sekoju", "noone": "neviens", - "title": "Notify me when" + "title": "Paziņot man, kad" } }, "preference": { "title": "Uzstādījumi", - "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" + "true_black_dark_mode": "Īsti melns tumšais režīms", + "disable_avatar_animation": "Atspējot animētos avatarus", + "disable_emoji_animation": "Atspējot animētās emocijzīmes", + "using_default_browser": "Saišu atvēršana noklusētajā pārlūkā", + "open_links_in_mastodon": "Atvērt saites Mastodon" }, "boring_zone": { - "title": "The Boring Zone", + "title": "Garlaicīgā zona", "account_settings": "Konta iestatījumi", "terms": "Pakalpojuma noteikumi", "privacy": "Privātuma politika" }, "spicy_zone": { - "title": "The Spicy Zone", - "clear": "Clear Media Cache", + "title": "Pikantā zona", + "clear": "Notīrīt Multivides Kešatmiņu", "signout": "Iziet" } }, @@ -645,7 +668,7 @@ "mastodon_description": "Mastodon ir atvērtā koda programmatūra. Tu vari ziņot par problēmām GitHub %s (%s)" }, "keyboard": { - "close_settings_window": "Close Settings Window" + "close_settings_window": "Aizvērt Iestatījumu Logu" } }, "report": { @@ -653,24 +676,24 @@ "title": "Ziņot %s", "step1": "1. solis no 2", "step2": "2. solis no 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.", + "content1": "Vai ir vēl kādas ziņas, kuras vēlies pievienot pārskatam?", + "content2": "Vai moderatoriem ir kaut kas jāzina par šo ziņojumu?", + "report_sent_title": "Paldies, ka ziņoji, mēs to izskatīsim.", "send": "Nosūtīt Sūdzību", "skip_to_send": "Sūtīt bez komentāra", - "text_placeholder": "Type or paste additional comments", - "reported": "REPORTED", + "text_placeholder": "Ieraksti vai ielīmē papildu komentārus", + "reported": "ZIŅOTS", "step_one": { "step_1_of_4": "1. solis no 4", - "whats_wrong_with_this_post": "What's wrong with this post?", - "whats_wrong_with_this_account": "What's wrong with this account?", - "whats_wrong_with_this_username": "What's wrong with %s?", + "whats_wrong_with_this_post": "Kas vainas šim ierakstam?", + "whats_wrong_with_this_account": "Kas vainas šim kontam?", + "whats_wrong_with_this_username": "Kas vainas %s?", "select_the_best_match": "Izvēlieties labāko atbilstību", "i_dont_like_it": "Man tas nepatīk", "it_is_not_something_you_want_to_see": "Tas nav kaut kas, ko tu vēlies redzēt", "its_spam": "Tas ir spams", - "malicious_links_fake_engagement_or_repetetive_replies": "Malicious links, fake engagement, or repetetive replies", - "it_violates_server_rules": "It violates server rules", + "malicious_links_fake_engagement_or_repetetive_replies": "Ļaunprātīgas saites, viltus iesaistīšana vai atkārtotas atbildes", + "it_violates_server_rules": "Tas pārkāpj servera noteikumus", "you_are_aware_that_it_breaks_specific_rules": "Tu zini, ka tas pārkāpj īpašus noteikumus", "its_something_else": "Tas ir kaut kas cits", "the_issue_does_not_fit_into_other_categories": "Šis jautājums neietilpst citās kategorijās" @@ -679,7 +702,7 @@ "step_2_of_4": "2. solis no 4", "which_rules_are_being_violated": "Kuri noteikumi tiek pārkāpti?", "select_all_that_apply": "Atlasi visus atbilstošos", - "i_just_don’t_like_it": "I just don’t like it" + "i_just_don’t_like_it": "Man vienkārši tas nepatīk" }, "step_three": { "step_3_of_4": "3. solis no 4", @@ -692,36 +715,48 @@ }, "step_final": { "dont_want_to_see_this": "Vai nevēlies to redzēt?", - "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", + "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "Kad pakalpojumā Mastodon redzi kaut ko, kas tev nepatīk, tu vari noņemt šo personu no savas pieredzes.", "unfollow": "Atsekot", "unfollowed": "Atsekoja", "unfollow_user": "Atsekot %s", "mute_user": "Apklusināt %s", - "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", + "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "Tu neredzēsi viņu ziņas vai reblogus savā mājas plūsmā. Viņi nezinās, ka ir izslēgti.", "block_user": "Bloķēt %s", - "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.", + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "Viņi vairs nevarēs sekot tavām ziņām vai redzēt tās, taču varēs redzēt, vai viņi ir bloķēti.", "while_we_review_this_you_can_take_action_against_user": "Kamēr mēs to izskatām, tu vari veikt darbības pret @%s" } }, "preview": { "keyboard": { - "close_preview": "Close Preview", - "show_next": "Show Next", - "show_previous": "Show Previous" + "close_preview": "Aizvērt Priekšskatījumu", + "show_next": "Rādīt Nākamo", + "show_previous": "Rādīt Iepriekšējo" } }, "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": "Pašreizējais atlasītais profils: %s. Veic dubultskārienu un pēc tam turi, lai parādītu konta pārslēdzēju", + "dismiss_account_switcher": "Noraidīt Konta Pārslēdzēju", "add_account": "Pievienot kontu" }, "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": "Jaunums Mastodonā", + "multiple_account_switch_intro_description": "Pārslēdzies starp vairākiem kontiem, turot nospiestu profila pogu.", + "accessibility_hint": "Veic dubultskārienu, lai noraidītu šo vedni" }, "bookmark": { - "title": "Bookmarks" + "title": "Grāmatzīmes" + }, + "followed_tags": { + "title": "Sekotie Tēmturi", + "header": { + "posts": "ziņas", + "participants": "dalībnieki", + "posts_today": "ziņas šodien" + }, + "actions": { + "follow": "Sekot", + "unfollow": "Atsekot" + } } } } diff --git a/Localization/StringsConvertor/input/lv.lproj/ios-infoPlist.json b/Localization/StringsConvertor/input/lv.lproj/ios-infoPlist.json index c6db73de0..860333e51 100644 --- a/Localization/StringsConvertor/input/lv.lproj/ios-infoPlist.json +++ b/Localization/StringsConvertor/input/lv.lproj/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": "Izmanto, lai fotografētu ziņas statusu", + "NSPhotoLibraryAddUsageDescription": "Izmanto, lai saglabātu fotoattēlu Photo Library", + "NewPostShortcutItemTitle": "Jauna Ziņa", + "SearchShortcutItemTitle": "Meklēt" } diff --git a/Localization/StringsConvertor/input/my.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/my.lproj/Localizable.stringsdict new file mode 100644 index 000000000..8230962a5 --- /dev/null +++ b/Localization/StringsConvertor/input/my.lproj/Localizable.stringsdict @@ -0,0 +1,407 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + မဖတ်ရသေးသောအသိပေးချက် %ld ခု ရှိသည် + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + စာလုံးရေ သတ်မှတ်ချက်ထက် %#@character_count@ လုံး ထက်ကျော်လွန် + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + စာလုံး %ld လုံး + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + သတ်မှတ်စာလုံးရေ %#@character_count@ လုံး ကျန်ရှိ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + စာလုံး %ld လုံး + + + a11y.plural.count.characters_left + + NSStringLocalizedFormatKey + စာလုံးရေ %#@character_count@ လုံး ကျန်ရှိ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + စာလုံး %ld လုံး + + + plural.count.followed_by_and_mutual + + NSStringLocalizedFormatKey + %#@names@%#@count_mutual@ + names + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + + + count_mutual + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %1$@ နှင့် ဘုံသူငယ်ချင်း %ld ဦးမှ စောင့်ကြည့်နေသည် + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + ပို့စ်များ + + + plural.count.media + + NSStringLocalizedFormatKey + %#@media_count@ + media_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + ရုပ်သံ %ld ခု + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + ပို့စ် %ld ခု + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + အကြိုက်ဆုံး %ld ခု + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + ပြန်မျှဝေမှု %ld ခု + + + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + ပြန်စာ %ld ခု + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + မဲ %ld မဲ + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + မဲပေးသူ %ld ဦး + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + လူ %ld ဦး ပြောနေသည် + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + စောင့်ကြည့်သူ %ld ဦး + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + စောင့်ကြည့်သူ %ld ဦး + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld နှစ် ကျန်ရှိ + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld လ ကျန်ရှိ + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld ရက် ကျန်ရှိ + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld နာရီ ကျန်ရှိ + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld မိနစ် ကျန်ရှိ + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld စက္ကန့် ကျန်ရှိ + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + လွန်ခဲ့သော %ld နှစ်က + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + လွန်ခဲ့သော %ld လက + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + လွန်ခဲ့သော %ld ရက်က + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + လွန်ခဲ့သော %ld နာရီက + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + လွန်ခဲ့သော %ld မိနစ်က + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + လွန်ခဲ့သော %ld စက္ကန့်က + + + + diff --git a/Localization/StringsConvertor/input/my.lproj/app.json b/Localization/StringsConvertor/input/my.lproj/app.json new file mode 100644 index 000000000..ea235fa53 --- /dev/null +++ b/Localization/StringsConvertor/input/my.lproj/app.json @@ -0,0 +1,762 @@ +{ + "common": { + "alerts": { + "common": { + "please_try_again": "ပြန်လည်ကြိုးစားကြည့်ပါ", + "please_try_again_later": "နောက်မှ ပြန်လည်ကြိုးစားကြည့်ပါ" + }, + "sign_up_failure": { + "title": "အကောင့်ဖွင့်ခြင်း မအောင်မြင်ပါ" + }, + "server_error": { + "title": "ဆာဗာ အမှား" + }, + "vote_failure": { + "title": "မဲပေးမှု မအောင်မြင်ခြင်း", + "poll_ended": "စစ်တမ်းကောက်မှု ပြီးဆုံးပါပြီ" + }, + "discard_post_content": { + "title": "မူကြမ်းကို ပယ်ဖျက်ပါ", + "message": "ရေးသားထားသောမူကြမ်းကို ပယ်ဖျက်ရန် အတည်ပြုပါ" + }, + "publish_post_failure": { + "title": "ပို့စ်တင်ခြင်း မအောင်မြင်မှု", + "message": "ပို့စ်တင်ခြင်း မအောင်မြင်ပါ၊ သင်၏ အင်တာနက်ချိတ်ဆက်မှုကို စစ်ဆေးပါ။", + "attachments_message": { + "video_attach_with_photo": "ဓာတ်ပုံများပါဝင်သော ပို့စ်တွင် ဗီဒီိယိုကို တွဲတင်၍ မရပါ", + "more_than_one_video": "ဗီဒီိယို ၁ ခုထက်ပို၍ တွဲတင်၍ မရပါ" + } + }, + "edit_profile_failure": { + "title": "ပရိုဖိုင်ပြင်ဆင်ခြင်း အမှား", + "message": "ပရိုဖိုင်ကို ပြင်ဆင်၍ မရပါ၊ ပြန်လည်ကြိုးစားကြည့်ပါ။" + }, + "sign_out": { + "title": "ထွက်မည်", + "message": "အကောင့်မှ ထွက်ရန် သေချာပါသလား?", + "confirm": "ထွက်မည်" + }, + "block_domain": { + "title": "%s တစ်ခုလုံးကို ဘလော့လုပ်ရန် တကယ် သေချာပါသလား? များသောအားဖြင့် အနည်းစုကို ပစ်မှတ်ထား ဘလော့လုပ်ခြင်းသည် လုံလောက်ပါသည်။ ထို ဒိုမိန်းမှ အကြောင်းအရာ တစ်ခုမှ မြင်ရမည်မဟုတ်သည့်အပြင် ထို ဒိုမိန်းတွင်ရှိသော သင်၏ စောင့်ကြည့်သူများပါ ဖယ်ရှားပစ်မည်ဖြစ်သည်။", + "block_entire_domain": "ဒိုမိန်းကို ဘလော့လုပ်ရန်" + }, + "save_photo_failure": { + "title": "ဓာတ်ပုံသိမ်းဆည်းခြင်း အမှား", + "message": "ကျေးဇူးပြု၍ ဓာတ်ပုံသိမ်းဆည်းနိုင်ရန် ဓာတ်ပုံပြတိုက်သို့ ဝင်ရောက်ခွင့်ပေးပါ။" + }, + "delete_post": { + "title": "ပို့စ်ဖျက်ရန်", + "message": "ပို့စ်ကို ဖျက်ရန် သေချာပါသလား?" + }, + "clean_cache": { + "title": "Cache ကို ရှင်းပါ", + "message": "%s cache ကို အောင်မြင်စွာ ရှင်းလင်းပြီးပါပြီ" + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" + } + }, + "controls": { + "actions": { + "back": "ပြန်၍", + "next": "ရှေ့သို့", + "previous": "ယခင်", + "open": "ဖွင့်", + "add": "ထည့်", + "remove": "ဖယ်ရှား", + "edit": "တည်းဖြတ်", + "save": "သိမ်းဆည်း", + "ok": "အိုကေ", + "done": "ပြီးပြီ", + "confirm": "အတည်ပြု", + "continue": "ဆက်လက်", + "compose": "ရေးဖွဲ့", + "cancel": "ပယ်ဖျက်", + "discard": "ဖယ်ရှား", + "try_again": "ထပ်မံကြိုးစားပါ", + "take_photo": "ဓါတ်ပုံရိုက်", + "save_photo": "ဓါတ်ပုံသိမ်းဆည်း", + "copy_photo": "ဓာတ်ပုံကူး", + "sign_in": "လော့ဂ်အင်ဝင်", + "sign_up": "အကောင့်ဖန်တီး", + "see_more": "ပိုမိုကြည့်ရှုရန်", + "preview": "အစမ်းကြည့်", + "copy": "Copy", + "share": "မျှဝေ", + "share_user": "%s ကို မျှဝေပါ", + "share_post": "ပို့စ်ကို မျှဝေရန်", + "open_in_safari": "Safari တွင် ဖွင့်ရန်", + "open_in_browser": "Browser တွင် ဖွင့်ရန်", + "find_people": "စောင့်ကြည့်ရန် လူရှာပါ", + "manually_search": "ကိုယ်တိုင် ရှာဖွေရန်", + "skip": "ကျော်", + "reply": "စာပြန်", + "report_user": " %s ကို တိုင်ကြားရန်", + "block_domain": "%s ကို ဘလော့လုပ်ရန်", + "unblock_domain": "%s ကို ဘလော့ဖြုတ်ရန်", + "settings": "ဆက်တင်များ", + "delete": "ဖျက်", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } + }, + "tabs": { + "home": "အိမ်", + "search_and_explore": "Search and Explore", + "notifications": "အသိပေးချက်များ", + "profile": "ကိုယ်ရေးမှတ်တမ်း" + }, + "keyboard": { + "common": { + "switch_to_tab": "%s သို့ ပြောင်းရန်", + "compose_new_post": "ပို့စ်အသစ် ရေးဖွဲ့", + "show_favorites": "အကြိုက်ဆုံးများ ပြရန်", + "open_settings": "ဆက်တင်ကို ဖွင့်ရန်" + }, + "timeline": { + "previous_status": "ယခင်ပို့စ်", + "next_status": "နောက်ပို့စ်", + "open_status": "ပို့စ်ဖွင့်ရန်", + "open_author_profile": "စာရေးသူ၏ ပရိုဖိုင်ကို ဖွင့်ပါ", + "open_reblogger_profile": "ပြန်တင်သူ၏ ပရိုဖိုင်ကို ဖွင့်ပါ", + "reply_status": "ပို့စ်ကို စာပြန်", + "toggle_reblog": "ပို့စ်ကိုပြန်တင်ခွင့်ပေးခြင်းကို ဖွင့်၊ပိတ် လုပ်ပါ", + "toggle_favorite": "အကြိုက်ဆုံးလုပ်ခွင့်ပေးခြင်းကို ဖွင့်၊ပိတ် လုပ်ပါ", + "toggle_content_warning": "အကြောင်းအရာသတိပေးချက်ကို ဖွင့်၊ပိတ် လုပ်ပါ", + "preview_image": "ဓာတ်ပုံကို ကြိုကြည့်" + }, + "segmented_control": { + "previous_section": "ယခင်အပိုင်း", + "next_section": "နောက်အပိုင်း" + } + }, + "status": { + "user_reblogged": "%s ကို ပြန်တင်", + "user_replied_to": "%s ထံ စာပြန်", + "show_post": "ပို့စ်ကို ပြသ", + "show_user_profile": "အသုံးပြုသူ၏ ပရိုဖိုင်ကို ပြရန်", + "content_warning": "အကြောင်းအရာသတိပေးချက်", + "sensitive_content": "ထိလွယ်ရှလွယ် အကြောင်းအရာ", + "media_content_warning": "ဖော်ထုတ်ရန် မည်သည့်နေရာမဆို နှိပ်ပါ", + "tap_to_reveal": "ဖော်ထုတ်ရန် နှိပ်ပါ", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", + "poll": { + "vote": "မဲပေး", + "closed": "ပိတ်သွားပြီ" + }, + "meta_entity": { + "url": "လင့်ခ်: %s", + "hashtag": "ဟက်ရှ်တက်ခ်: %s", + "mention": "ပရိုဖိုင် ပြသ: %s", + "email": "အီးမေးလ်လိပ်စာ: %s" + }, + "actions": { + "reply": "စာပြန်", + "reblog": "ပြန်တင်", + "unreblog": "ပြန်တင်ခြင်းကို ပယ်ဖျက်", + "favorite": "အကြိုက်ဆုံး", + "unfavorite": "အကြိုက်ဆုံးမှ ဖယ်ရှားရန်", + "menu": "မီနူး", + "hide": "ဝှက်ရန်", + "show_image": "ဓာတ်ပုံပြရန်", + "show_gif": "GIF ပြရန်", + "show_video_player": "ဗီဒီယိုဖွင့်စက် ပြရန်", + "share_link_in_post": "Share Link in Post", + "tap_then_hold_to_show_menu": "မီနူးပြရန် ဖိထားပါ" + }, + "tag": { + "url": "URL", + "mention": "ရည်ညွှန်း", + "link": "လင့်ခ်", + "hashtag": "ဟက်ရှ်တက်ခ်", + "email": "အီးမေးလ်", + "emoji": "အီမိုဂျီ" + }, + "visibility": { + "unlisted": "ဒီပို့စ်ကို လူတိုင်းမြင်နိုင်သည်၊ သို့သော် အများမြင်အလင်းစဉ်တွင် မပြသပါ။", + "private": "သူတို့၏ စောင့်ကြည့်သူများသာ ဒီပို့စ်ကို မြင်နိုင်သည်", + "private_from_me": "ကျွန်ုပ်၏ စောင့်ကြည့်သူများသာ ဒီပို့စ်ကို မြင်နိုင်သည်", + "direct": "ရည်ညွှန်းခံရသောအသုံးပြုသူများသာ ဒီပို့စ်ကို မြင်နိုင်သည်" + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" + } + }, + "friendship": { + "follow": "စောင့်ကြည့်ရန်", + "following": "စောင့်ကြည့်နေသည်", + "request": "တောင်းဆို", + "pending": "ဆိုင်းငံ့ထားသည်", + "block": "ဘလော့လုပ်ရန်", + "block_user": "%s ကို ဘလော့လုပ်ရန်", + "block_domain": "%s ကို ဘလော့လုပ်ရန်", + "unblock": "ဘလော့ဖြုတ်ရန်", + "unblock_user": "%s ကို ဘလော့ဖြုတ်ရန်", + "blocked": "ဘလော့ထားသည်", + "mute": "ပိတ်ထားရန်", + "mute_user": "%s ကို ပိတ်ထားရန်", + "unmute": "ပြန်ဖွင့်ရန်", + "unmute_user": "%s ကို ပြန်ဖွင့်ရန်", + "muted": "ပိတ်ထားဆဲ", + "edit_info": "အချက်အလက်တည်းဖြတ်", + "show_reblogs": "ပြန်တင်ထားတာတွေ ပြရန်", + "hide_reblogs": "ပြန်တင်ထားတာတွေ ဖျောက်ရန်" + }, + "timeline": { + "filtered": "စစ်ထုတ်ထားသည်", + "timestamp": { + "now": "ယခု" + }, + "loader": { + "load_missing_posts": "ပျောက်နေသော ပို့စ်များကို လုဒ်ပါ", + "loading_missing_posts": "ပျောက်နေသော ပို့စ်များကို လုဒ်ပါ...", + "show_more_replies": "ပြန်စာများထပ်ပြပါ" + }, + "header": { + "no_status_found": "ပို့စ်ရှာမတွေ့ပါ", + "blocking_warning": "ဒီအသုံးပြုသူ၏ ပရိုဖိုင်ကို ဘလော့မဖြုတ်မချင်း ကြည့်၍မရပါ၊ သင်၏ ပရိုဖိုင်သည် ထိုသူတို့ထံ ဤကဲ့သို့ ပေါ်နေပါမည်။", + "user_blocking_warning": "%s ၏ ပရိုဖိုင်ကို ဘလော့မဖြုတ်မချင်း ကြည့်၍မရပါ၊ သင်၏ ပရိုဖိုင်သည် ထိုသူ့ထံ ဤကဲ့သို့ ပေါ်နေပါမည်။", + "blocked_warning": "ဤပုဂ္ဂိုလ်မှ သင့်ကို ဘလော့မဖြုတ်မချင်း သူ၏ ပရိုဖိုင်သည် သင် ကြည့်၍မရပါ။", + "user_blocked_warning": "%s မှ သင့်ကို ဘလော့မဖြုတ်မချင်း သူ၏ ပရိုဖိုင်သည် သင် ကြည့်၍မရပါ။", + "suspended_warning": "ဤအသုံးပြုသူသည် ဆိုင်းငံ့ခံထားရသည်။", + "user_suspended_warning": "%s ၏အကောင့်သည် ဆိုင်းငံ့ခံထားရသည်။" + } + } + } + }, + "scene": { + "welcome": { + "slogan": "လူမှုကွန်ယက်ကို သင်၏လက်ထဲသို့ ပြန်လည်ထည့်ပေးလိုက်ပြီ။", + "get_started": "စတင်ရန်", + "log_in": "လော့ခ်အင်ဝင်ရန်" + }, + "login": { + "title": "ပြန်လည်ကြိုဆိုပါသည်", + "subtitle": "သင်၏အကောင့်ဖွင့်ခဲ့သော ဆာဗာပေါ်တွင် လော့ခ်အင်ဝင်ရောက်ပါ", + "server_search_field": { + "placeholder": "URL ကို ထည့်သွင်းပါ (သို့) သင်၏ ဆာဗာကို ရှာပါ" + } + }, + "server_picker": { + "title": "Mastodon ကို အသိုင်းအဝန်းပေါင်းစုံမှ အသုံးပြုသူများဖြင့် ဖွဲ့စည်းထားသည်။", + "subtitle": "သင်၏ ဒေသ၊ စိတ်ဝင်စားမှု အပေါ်အခြေခံသော ဆာဗာတစ်ခု ရွေးချယ်ပါ၊ မည်သည့်ဆာဗာကို ရွေးချယ်ထားစေကာမူ အခြားအသုံးပြုသူများနှင့် ပုံမှန်အတိုင်း ဆက်သွယ်နိုင်သည်။", + "button": { + "category": { + "all": "အားလုံး", + "all_accessiblity_description": "အမျိုးအစား - အားလုံး", + "academia": "ပညာရှင်", + "activism": "တက်ကြွလှုပ်ရှားမှု", + "food": "အစားအစာ", + "furry": "furry", + "games": "ဂိမ်း", + "general": "အထွေထွေ", + "journalism": "သတင်းစာပညာ", + "lgbt": "lgbt", + "regional": "နယ်မြေဆိုင်ရာ", + "art": "အနုပညာ", + "music": "ဂီတ", + "tech": "နည်းပညာ" + }, + "see_less": "လျှော့ ကြည့်ရန်", + "see_more": "ပိုမိုကြည့်ရှုရန်" + }, + "label": { + "language": "ဘာသာစကား", + "users": "အသုံးပြုသူများ", + "category": "အမျိုးအစား" + }, + "input": { + "search_servers_or_enter_url": "အသိုင်းအဝိုင်းများကို ရှာဖွေ (သို့) URL ကို ဝင်ရောက်" + }, + "empty_state": { + "finding_servers": "အဆင်သင့်သုံးရသော ဆာဗာများကို ရှာနေသည်...", + "bad_network": "ဒေတာဖွင့်နေစဉ် တစ်ခုခုမှားယွင်းသွားသည်၊ အင်တာနက်ချိတ်ဆက်မှုကို စစ်ဆေးပါ။", + "no_results": "ရလဒ်မရှိပါ" + } + }, + "register": { + "title": "သင့်ကို %s တွင် စတင်လိုက်ရအောင်", + "lets_get_you_set_up_on_domain": "သင့်ကို %s တွင် စတင်လိုက်ရအောင်", + "input": { + "avatar": { + "delete": "ဖျက်" + }, + "username": { + "placeholder": "အသုံးပြုသူအမည်", + "duplicate_prompt": "ဤအသုံးပြုသူအမည်သည် ရှိနှင့်ပြီးဖြစ်သည်။" + }, + "display_name": { + "placeholder": "ပြသမည့် အမည်" + }, + "email": { + "placeholder": "အီးမေးလ်" + }, + "password": { + "placeholder": "စကားဝှက်", + "require": "သင်၏စကားဝှက်သည် အနည်းဆုံးလိုအပ်သည်:", + "character_limit": "အက္ခရာ ၈ လုံး", + "accessibility": { + "checked": "စစ်ဆေးပြီးပြီ", + "unchecked": "မစစ်ဆေးခဲ့ပါ" + }, + "hint": "စကားဝှက်သည် အနည်းဆုံး အက္ခရာ ၈ လုံး ရှိရပါမည်။" + }, + "invite": { + "registration_user_invite_request": "သင် ဘာကြောင့် ပါဝင်ချင်တာပါလဲ?" + } + }, + "error": { + "item": { + "username": "အသုံးပြုသူအမည်", + "email": "အီးမေးလ်", + "password": "စကားဝှက်", + "agreement": "သဘောတူညီမှု", + "locale": "ဒေသဆိုင်ရာ", + "reason": "အကြောင်းပြချက်" + }, + "reason": { + "blocked": "%s တွင် ခွင့်မပြုထားသော အီးမေးလ်ထောက်ပံ့သူပါဝင်နေသည်။", + "unreachable": "%s တည်ရှိပုံ မပေါ်ပါ", + "taken": "%s ကို အသုံးပြုနေသူ ရှိနှင့်ပြီးဖြစ်သည်။", + "reserved": "%s သည် သီးသန့်ဖယ်ထားသောစကားလုံး ဖြစ်သည်။", + "accepted": "%s ကို လက်ခံရမည်ဖြစ်သည်", + "blank": "%s ကို လိုအပ်သည်", + "invalid": "%s သည် မခိုင်လုံပါ", + "too_long": "%s သည် ရှည်လွန်းသည်", + "too_short": "%s သည် တိုလွန်းသည်", + "inclusion": "%s သည် ထောက်ပံ့ထားသောတန်ဖိုး မဟုတ်ပါ" + }, + "special": { + "username_invalid": "အသုံးပြုသူအမည်တွင် ဂဏန်းအက္ခရာစာလုံးနှင့် အောက်မျဉ်း သာလျှင် ပါဝင်နိုင်သည်", + "username_too_long": "အသုံးပြုသူအမည်ရှည်လွန်းသည် (စာလုံး ၃၀ လုံးထက် ရှည်၍ မရပါ)", + "email_invalid": "ဤအီးမေးလ်လိပ်စာသည် ခိုင်လုံမှု မရှိပါ", + "password_too_short": "စကားဝှက်တိုလွန်းသည် (အနည်းဆုံး စာလုံး ၈ လုံး ရှိရမည်)" + } + } + }, + "server_rules": { + "title": "အခြေခံမှုအချို့", + "subtitle": "ဤစည်းမျဉ်းများကို ထိန်းညှိသူ %s ယောက်က သတ်မှတ်ကွပ်ကဲသည်။", + "prompt": "ဆက်လက်သွားမည်ဆိုပါက သင်သည် %s အတွက် ဝန်ဆောင်မှုနှင့် ကိုယ်ရေးကိုယ်တာမူဝါဒများကို လိုက်နာရမည်ဖြစ်သည်။", + "terms_of_service": "ဝန်ဆောင်မှုစည်းကမ်းချက်များ", + "privacy_policy": "ကိုယ်ရေးကိုယ်တာမူဝါဒ", + "button": { + "confirm": "သဘောတူညီသည်" + } + }, + "confirm_email": { + "title": "နောက််ဆုံးတစ်ခု", + "subtitle": "သင့်ကို ပို့လိုက်သောအီးမေးလ်တွင် ပါဝင်သည့်လင့်ခ်ကို နှိပ်ပါ။", + "tap_the_link_we_emailed_to_you_to_verify_your_account": "သင့်ကို ပို့လိုက်သောအီးမေးလ်တွင် ပါဝင်သည့်လင့်ခ်ကို နှိပ်ပါ။", + "button": { + "open_email_app": "အီးမေးလ်ကို ဖွင့်ပါ", + "resend": "ပြန်ပို့ပါ" + }, + "dont_receive_email": { + "title": "သင့်အီးမေးလ်ကို စစ်ကြည့်ပါ", + "description": "Check if your email address is correct as well as your junk folder if you haven’t.", + "resend_email": "အီးမေးလ်ကိုပြန်ပို့ပါ" + }, + "open_email_app": { + "title": "သင်၏စာဝင်ပုံးကို စစ်ဆေးပါ", + "description": "We just sent you an email. Check your junk folder if you haven’t.", + "mail": "မေးလ်", + "open_email_client": "Open Email Client" + } + }, + "home_timeline": { + "title": "အိမ်", + "navigation_bar_state": { + "offline": "အော့ဖ်လိုင်း", + "new_posts": "ပို့စ်အသစ်ကြည့်ရန်", + "published": "တင်လိုက်ပါပြီ!", + "Publishing": "ပို့စ်ကို တင်နေသည်...", + "accessibility": { + "logo_label": "လိုဂိုခလုတ်", + "logo_hint": "Tap to scroll to top and tap again to previous location" + } + } + }, + "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_reply": "စာပြန်အသစ်" + }, + "media_selection": { + "camera": "ဓါတ်ပုံရိုက်", + "photo_library": "ဓာတ်ပုံပြတိုက်", + "browse": "ရှာဖွေ" + }, + "content_input_placeholder": "Type or paste what’s on your mind", + "compose_action": "ပို့စ်တင်", + "replying_to_user": "%s ထံ စာပြန်နေသည်", + "attachment": { + "photo": "ဓာတ်ပုံ", + "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...", + "load_failed": "Load Failed", + "upload_failed": "Upload Failed", + "can_not_recognize_this_media_attachment": "Can not recognize this media attachment", + "attachment_too_large": "Attachment too large", + "compressing_state": "Compressing...", + "server_processing_state": "Server Processing..." + }, + "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", + "the_poll_is_invalid": "The poll is invalid", + "the_poll_has_empty_option": "The poll has empty option" + }, + "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", + "post_options": "Post Options", + "posting_as": "Posting as %s" + }, + "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": "မြင်နိုင်စွမ်း ရွေးချယ်ရန် - %s" + } + }, + "profile": { + "header": { + "follows_you": "Follows You" + }, + "dashboard": { + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" + }, + "fields": { + "joined": "Joined", + "add_row": "Add Row", + "placeholder": { + "label": "Label", + "content": "Content" + }, + "verified": { + "short": "Verified on %s", + "long": "Ownership of this link was checked on %s" + } + }, + "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" + }, + "confirm_show_reblogs": { + "title": "Show Reblogs", + "message": "Confirm to show reblogs" + }, + "confirm_hide_reblogs": { + "title": "Hide Reblogs", + "message": "Confirm to hide reblogs" + } + }, + "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": { + "title": "follower", + "footer": "Followers from other servers are not displayed." + }, + "following": { + "title": "following", + "footer": "Follows from other servers are not displayed." + }, + "familiarFollowers": { + "title": "Followers you familiar", + "followed_by_names": "Followed by %s" + }, + "favorited_by": { + "title": "Favorited By" + }, + "reblogged_by": { + "title": "Reblogged By" + }, + "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" + } + }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "community": "Community", + "for_you": "For You" + }, + "intro": "These are the posts gaining traction in your corner of Mastodon." + }, + "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" + }, + "follow_request": { + "accept": "Accept", + "accepted": "Accepted", + "reject": "reject", + "rejected": "Rejected" + } + }, + "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", + "step_one": { + "step_1_of_4": "Step 1 of 4", + "whats_wrong_with_this_post": "What's wrong with this post?", + "whats_wrong_with_this_account": "What's wrong with this account?", + "whats_wrong_with_this_username": "What's wrong with %s?", + "select_the_best_match": "Select the best match", + "i_dont_like_it": "I don’t like it", + "it_is_not_something_you_want_to_see": "It is not something you want to see", + "its_spam": "It’s spam", + "malicious_links_fake_engagement_or_repetetive_replies": "Malicious links, fake engagement, or repetetive replies", + "it_violates_server_rules": "It violates server rules", + "you_are_aware_that_it_breaks_specific_rules": "You are aware that it breaks specific rules", + "its_something_else": "It’s something else", + "the_issue_does_not_fit_into_other_categories": "The issue does not fit into other categories" + }, + "step_two": { + "step_2_of_4": "Step 2 of 4", + "which_rules_are_being_violated": "Which rules are being violated?", + "select_all_that_apply": "Select all that apply", + "i_just_don’t_like_it": "I just don’t like it" + }, + "step_three": { + "step_3_of_4": "Step 3 of 4", + "are_there_any_posts_that_back_up_this_report": "Are there any posts that back up this report?", + "select_all_that_apply": "Select all that apply" + }, + "step_four": { + "step_4_of_4": "Step 4 of 4", + "is_there_anything_else_we_should_know": "Is there anything else we should know?" + }, + "step_final": { + "dont_want_to_see_this": "Don’t want to see this?", + "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", + "unfollow": "Unfollow", + "unfollowed": "Unfollowed", + "unfollow_user": "Unfollow %s", + "mute_user": "Mute %s", + "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", + "block_user": "Block %s", + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.", + "while_we_review_this_you_can_take_action_against_user": "While we review this, you can take action against %s" + } + }, + "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" + }, + "bookmark": { + "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } + } + } +} diff --git a/Localization/StringsConvertor/input/my.lproj/ios-infoPlist.json b/Localization/StringsConvertor/input/my.lproj/ios-infoPlist.json new file mode 100644 index 000000000..b56ff5096 --- /dev/null +++ b/Localization/StringsConvertor/input/my.lproj/ios-infoPlist.json @@ -0,0 +1,6 @@ +{ + "NSCameraUsageDescription": "ပို့စ်အခြေအနေအတွက် ပုံရိုက်ရန် အသုံးပြုခဲ့သည်", + "NSPhotoLibraryAddUsageDescription": "ဓာတ်ပုံပြခန်းတွင် ပုံသိမ်းရန် အသုံးပြုခဲ့သည်", + "NewPostShortcutItemTitle": "ပို့စ်အသစ်", + "SearchShortcutItemTitle": "ရှာဖွေရန်" +} diff --git a/Localization/StringsConvertor/input/nl.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/nl.lproj/Localizable.stringsdict index 84769b0c1..29d0ec841 100644 --- a/Localization/StringsConvertor/input/nl.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/nl.lproj/Localizable.stringsdict @@ -15,7 +15,7 @@ one 1 unread notification other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds diff --git a/Localization/StringsConvertor/input/nl.lproj/app.json b/Localization/StringsConvertor/input/nl.lproj/app.json index 589c51d2d..938f40a07 100644 --- a/Localization/StringsConvertor/input/nl.lproj/app.json +++ b/Localization/StringsConvertor/input/nl.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Cache-geheugen Wissen", "message": "Cache-geheugen (%s) succesvol gewist." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -74,10 +79,11 @@ "take_photo": "Maak foto", "save_photo": "Bewaar foto", "copy_photo": "Kopieer foto", - "sign_in": "Log in", - "sign_up": "Create account", + "sign_in": "Inloggen", + "sign_up": "Account aanmaken", "see_more": "Meer", "preview": "Voorvertoning", + "copy": "Copy", "share": "Deel", "share_user": "Delen %s", "share_post": "Deel bericht", @@ -91,12 +97,16 @@ "block_domain": "Blokkeer %s", "unblock_domain": "Deblokkeer %s", "settings": "Instellingen", - "delete": "Verwijder" + "delete": "Verwijder", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Start", - "search": "Zoek", - "notification": "Melding", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Profiel" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Gevoelige inhoud", "media_content_warning": "Tap hier om te tonen", "tap_to_reveal": "Tik om te onthullen", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Stemmen", "closed": "Gesloten" @@ -139,8 +151,8 @@ "meta_entity": { "url": "Link: %s", "hashtag": "Hashtag: %s", - "mention": "Show Profile: %s", - "email": "Email address: %s" + "mention": "Profiel weergeven: %s", + "email": "E-mailadres: %s" }, "actions": { "reply": "Reageren", @@ -153,6 +165,7 @@ "show_image": "Toon afbeelding", "show_gif": "GIF weergeven", "show_video_player": "Toon videospeler", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tik en houd vast om menu te tonen" }, "tag": { @@ -168,6 +181,12 @@ "private": "Alleen hun volgers kunnen dit bericht zien.", "private_from_me": "Alleen mijn volgers kunnen dit bericht zien.", "direct": "Alleen de vermelde persoon kan dit bericht zien." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -187,8 +206,8 @@ "unmute_user": "%s niet langer negeren", "muted": "Genegeerd", "edit_info": "Bewerken", - "show_reblogs": "Show Reblogs", - "hide_reblogs": "Hide Reblogs" + "show_reblogs": "Toon reblogs", + "hide_reblogs": "Verberg reblogs" }, "timeline": { "filtered": "Gefilterd", @@ -219,15 +238,15 @@ "log_in": "Log in" }, "login": { - "title": "Welcome back", - "subtitle": "Log you in on the server you created your account on.", + "title": "Welkom terug", + "subtitle": "Log je in op de server waarop je je account hebt aangemaakt.", "server_search_field": { - "placeholder": "Enter URL or search for your server" + "placeholder": "Voer URL in of zoek naar uw server" } }, "server_picker": { "title": "Kies een server, welke dan ook.", - "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.", + "subtitle": "Kies een server gebaseerd op je regio, interesses, of een algemene server. Je kunt nog steeds chatten met iedereen op Mastodon, ongeacht op welke server je zit.", "button": { "category": { "all": "Alles", @@ -254,7 +273,7 @@ "category": "CATEGORIE" }, "input": { - "search_servers_or_enter_url": "Search communities or enter URL" + "search_servers_or_enter_url": "Zoek naar gemeenschappen of voer URL in" }, "empty_state": { "finding_servers": "Beschikbare servers zoeken...", @@ -264,7 +283,7 @@ }, "register": { "title": "Vertel ons over uzelf.", - "lets_get_you_set_up_on_domain": "Let’s get you set up on %s", + "lets_get_you_set_up_on_domain": "Laten we je account instellen op %s", "input": { "avatar": { "delete": "Verwijderen" @@ -335,7 +354,7 @@ "confirm_email": { "title": "Nog één ding.", "subtitle": "We hebben een e-mail gestuurd naar %s,\nklik op de link om uw account te bevestigen.", - "tap_the_link_we_emailed_to_you_to_verify_your_account": "Tap the link we emailed to you to verify your account", + "tap_the_link_we_emailed_to_you_to_verify_your_account": "Tik op de link in de e-mail die je hebt ontvangen om uw account te verifiëren", "button": { "open_email_app": "Email Openen", "resend": "Verstuur opnieuw" @@ -360,8 +379,8 @@ "published": "Gepubliceerd!", "Publishing": "Bericht publiceren...", "accessibility": { - "logo_label": "Logo Button", - "logo_hint": "Tap to scroll to top and tap again to previous location" + "logo_label": "Logo knop", + "logo_hint": "Tik om naar boven te scrollen en tik nogmaals om terug te keren naar de vorige locatie" } } }, @@ -388,12 +407,12 @@ "attachment_broken": "Deze %s is corrupt en kan niet geüpload worden naar Mastodon.", "description_photo": "Omschrijf de foto voor mensen met een visuele beperking...", "description_video": "Omschrijf de video voor mensen met een visuele beperking...", - "load_failed": "Load Failed", - "upload_failed": "Upload Failed", - "can_not_recognize_this_media_attachment": "Can not recognize this media attachment", - "attachment_too_large": "Attachment too large", - "compressing_state": "Compressing...", - "server_processing_state": "Server Processing..." + "load_failed": "Laden mislukt", + "upload_failed": "Uploaden mislukt", + "can_not_recognize_this_media_attachment": "Kan de media in de bijlage niet herkennen", + "attachment_too_large": "Bijlage te groot", + "compressing_state": "Bezig met comprimeren...", + "server_processing_state": "Server is bezig met verwerken..." }, "poll": { "duration_time": "Duur: %s", @@ -404,8 +423,8 @@ "three_days": "3 Dagen", "seven_days": "7 Dagen", "option_number": "Optie %ld", - "the_poll_is_invalid": "The poll is invalid", - "the_poll_has_empty_option": "The poll has empty option" + "the_poll_is_invalid": "De peiling is ongeldig", + "the_poll_has_empty_option": "De peiling heeft een lege optie" }, "content_warning": { "placeholder": "Schrijf hier een nauwkeurige waarschuwing..." @@ -427,8 +446,8 @@ "enable_content_warning": "Inhoudswaarschuwing inschakelen", "disable_content_warning": "Inhoudswaarschuwing Uitschakelen", "post_visibility_menu": "Berichtzichtbaarheidsmenu", - "post_options": "Post Options", - "posting_as": "Posting as %s" + "post_options": "Plaats Bericht Opties", + "posting_as": "Plaats bericht als %s" }, "keyboard": { "discard_post": "Bericht Verwijderen", @@ -441,22 +460,26 @@ }, "profile": { "header": { - "follows_you": "Follows You" + "follows_you": "Volgt jou" }, "dashboard": { - "posts": "berichten", - "following": "volgend", - "followers": "volgers" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Rij Toevoegen", "placeholder": { "label": "Etiket", "content": "Inhoud" }, "verified": { - "short": "Verified on %s", - "long": "Ownership of this link was checked on %s" + "short": "Geverifieerd op %s", + "long": "Eigendom van deze link is gecontroleerd op %s" } }, "segmented_control": { @@ -484,12 +507,12 @@ "message": "Bevestig om %s te deblokkeren" }, "confirm_show_reblogs": { - "title": "Show Reblogs", - "message": "Confirm to show reblogs" + "title": "Toon reblogs", + "message": "Bevestig om reblogs te tonen" }, "confirm_hide_reblogs": { - "title": "Hide Reblogs", - "message": "Confirm to hide reblogs" + "title": "Verberg reblogs", + "message": "Bevestig om reblogs te verbergen" } }, "accessibility": { @@ -500,16 +523,16 @@ } }, "follower": { - "title": "follower", + "title": "volger", "footer": "Volgers van andere servers worden niet weergegeven." }, "following": { - "title": "following", + "title": "volgend", "footer": "Volgers van andere servers worden niet weergegeven." }, "familiarFollowers": { - "title": "Followers you familiar", - "followed_by_names": "Followed by %s" + "title": "Volgers die je kent", + "followed_by_names": "Gevolgd door %s" }, "favorited_by": { "title": "Favorited By" @@ -555,7 +578,7 @@ "posts": "Berichten", "hashtags": "Hashtags", "news": "Nieuws", - "community": "Community", + "community": "Gemeenschap", "for_you": "Voor jou" }, "intro": "Dit zijn de berichten die populair zijn in jouw Mastodon-kringen." @@ -581,10 +604,10 @@ "show_mentions": "Vermeldingen weergeven" }, "follow_request": { - "accept": "Accept", - "accepted": "Accepted", - "reject": "reject", - "rejected": "Rejected" + "accept": "Accepteren", + "accepted": "Geaccepteerd", + "reject": "afwijzen", + "rejected": "Afgewezen" } }, "thread": { @@ -661,11 +684,11 @@ "text_placeholder": "Schrijf of plak aanvullende opmerkingen", "reported": "Gerapporteerd", "step_one": { - "step_1_of_4": "Step 1 of 4", - "whats_wrong_with_this_post": "What's wrong with this post?", - "whats_wrong_with_this_account": "What's wrong with this account?", - "whats_wrong_with_this_username": "What's wrong with %s?", - "select_the_best_match": "Select the best match", + "step_1_of_4": "Stap 1 van 4", + "whats_wrong_with_this_post": "Wat is er mis met dit bericht?", + "whats_wrong_with_this_account": "Wat is er mis met dit bericht?", + "whats_wrong_with_this_username": "Wat is er mis met %s?", + "select_the_best_match": "Selecteer de beste overeenkomst", "i_dont_like_it": "I don’t like it", "it_is_not_something_you_want_to_see": "It is not something you want to see", "its_spam": "It’s spam", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/pt-BR.lproj/app.json b/Localization/StringsConvertor/input/pt-BR.lproj/app.json index 60d858235..e680db924 100644 --- a/Localization/StringsConvertor/input/pt-BR.lproj/app.json +++ b/Localization/StringsConvertor/input/pt-BR.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Limpar Cache", "message": "%s do cache removidos com sucesso." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Criar conta", "see_more": "Ver mais", "preview": "Pré-visualização", + "copy": "Copy", "share": "Compartilhar", "share_user": "Compartilhar %s", "share_post": "Compartilhar postagem", @@ -91,12 +97,16 @@ "block_domain": "Bloquear %s", "unblock_domain": "Desbloquear %s", "settings": "Configurações", - "delete": "Excluir" + "delete": "Excluir", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Início", - "search": "Buscar", - "notification": "Notificação", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Perfil" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Conteúdo sensível", "media_content_warning": "Toque em qualquer lugar para revelar", "tap_to_reveal": "Toque para revelar", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Votar", "closed": "Fechado" @@ -153,6 +165,7 @@ "show_image": "Exibir imagem", "show_gif": "Exibir GIF", "show_video_player": "Mostrar reprodutor de vídeo", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Toque e em seguida segure para exibir o menu" }, "tag": { @@ -168,6 +181,12 @@ "private": "Somente seus seguidores podem ver essa postagem.", "private_from_me": "Somente meus seguidores podem ver essa postagem.", "direct": "Somente o usuário mencionado pode ver essa postagem." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Segue você" }, "dashboard": { - "posts": "toots", - "following": "seguindo", - "followers": "seguidores" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Adicionar linha", "placeholder": { "label": "Descrição", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Marcados" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/pt.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/pt.lproj/Localizable.stringsdict index eabdc3c32..788eb95fc 100644 --- a/Localization/StringsConvertor/input/pt.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/pt.lproj/Localizable.stringsdict @@ -15,7 +15,7 @@ one 1 unread notification other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds diff --git a/Localization/StringsConvertor/input/pt.lproj/app.json b/Localization/StringsConvertor/input/pt.lproj/app.json index 3113ada74..4939d3afb 100644 --- a/Localization/StringsConvertor/input/pt.lproj/app.json +++ b/Localization/StringsConvertor/input/pt.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Clean Cache", "message": "Successfully cleaned %s cache." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Create account", "see_more": "See More", "preview": "Preview", + "copy": "Copy", "share": "Share", "share_user": "Share %s", "share_post": "Share Post", @@ -91,12 +97,16 @@ "block_domain": "Block %s", "unblock_domain": "Unblock %s", "settings": "Settings", - "delete": "Delete" + "delete": "Delete", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Home", - "search": "Search", - "notification": "Notification", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Profile" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Sensitive Content", "media_content_warning": "Tap anywhere to reveal", "tap_to_reveal": "Tap to reveal", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Vote", "closed": "Closed" @@ -153,6 +165,7 @@ "show_image": "Show image", "show_gif": "Show GIF", "show_video_player": "Show video player", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Add Row", "placeholder": { "label": "Label", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/ro.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/ro.lproj/Localizable.stringsdict index 9df2162b0..669272590 100644 --- a/Localization/StringsConvertor/input/ro.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ro.lproj/Localizable.stringsdict @@ -15,9 +15,9 @@ one 1 unread notification few - %ld unread notification + %ld unread notifications other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds diff --git a/Localization/StringsConvertor/input/ro.lproj/app.json b/Localization/StringsConvertor/input/ro.lproj/app.json index 75a77184c..65ae8eb4e 100644 --- a/Localization/StringsConvertor/input/ro.lproj/app.json +++ b/Localization/StringsConvertor/input/ro.lproj/app.json @@ -13,7 +13,7 @@ }, "vote_failure": { "title": "Eșec la vot", - "poll_ended": "The poll has ended" + "poll_ended": "Sondajul tău s-a încheiat" }, "discard_post_content": { "title": "Șterge Schită", @@ -41,7 +41,7 @@ "block_entire_domain": "Block Domain" }, "save_photo_failure": { - "title": "Save Photo Failure", + "title": "Salvarea fotografiei a eșuat", "message": "Please enable the photo library access permission to save the photo." }, "delete_post": { @@ -51,17 +51,22 @@ "clean_cache": { "title": "Clean Cache", "message": "Successfully cleaned %s cache." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { "actions": { - "back": "Back", - "next": "Next", + "back": "Înapoi", + "next": "Înainte", "previous": "Previous", "open": "Deschide", - "add": "Add", + "add": "Adaugă", "remove": "Elimină", - "edit": "Edit", + "edit": "Modifică", "save": "Salvează", "ok": "OK", "done": "Done", @@ -78,25 +83,30 @@ "sign_up": "Create account", "see_more": "See More", "preview": "Preview", + "copy": "Copy", "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", + "open_in_browser": "Deschide în browser", + "find_people": "Găsește persoane de urmărit", "manually_search": "Manually search instead", - "skip": "Skip", + "skip": "Treci peste", "reply": "Reply", "report_user": "Report %s", "block_domain": "Block %s", "unblock_domain": "Unblock %s", "settings": "Settings", - "delete": "Delete" + "delete": "Delete", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { - "home": "Home", - "search": "Search", - "notification": "Notification", + "home": "Acasă", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Profile" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Sensitive Content", "media_content_warning": "Tap anywhere to reveal", "tap_to_reveal": "Tap to reveal", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Vote", "closed": "Closed" @@ -153,6 +165,7 @@ "show_image": "Show image", "show_gif": "Show GIF", "show_video_player": "Show video player", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Add Row", "placeholder": { "label": "Label", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/ru.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/ru.lproj/Localizable.stringsdict index c9552a9e4..d43386ad9 100644 --- a/Localization/StringsConvertor/input/ru.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/ru.lproj/Localizable.stringsdict @@ -15,11 +15,11 @@ one 1 unread notification few - %ld unread notification + %ld unread notifications many - %ld unread notification + %ld unread notifications other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds diff --git a/Localization/StringsConvertor/input/ru.lproj/app.json b/Localization/StringsConvertor/input/ru.lproj/app.json index 25314102a..bb34e4c1c 100644 --- a/Localization/StringsConvertor/input/ru.lproj/app.json +++ b/Localization/StringsConvertor/input/ru.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Очистка кэша", "message": "Успешно очищено %s кэша." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Create account", "see_more": "Ещё", "preview": "Предпросмотр", + "copy": "Copy", "share": "Поделиться", "share_user": "Поделиться %s", "share_post": "Поделиться постом", @@ -91,12 +97,16 @@ "block_domain": "Заблокировать %s", "unblock_domain": "Разблокировать %s", "settings": "Настройки", - "delete": "Удалить" + "delete": "Удалить", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Главная", - "search": "Поиск", - "notification": "Уведомление", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Профиль" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Sensitive Content", "media_content_warning": "Нажмите в любом месте, чтобы показать", "tap_to_reveal": "Нажмите, чтобы показать", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Проголосовать", "closed": "Завершён" @@ -153,6 +165,7 @@ "show_image": "Показать изображение", "show_gif": "Показать GIF", "show_video_player": "Показать видеопроигрыватель", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Нажмите и удерживайте, чтобы показать меню" }, "tag": { @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Подписан(а) на вас" }, "dashboard": { - "posts": "посты", - "following": "подписки", - "followers": "подписчики" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Добавить строку", "placeholder": { "label": "Ярлык", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/si.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/si.lproj/Localizable.stringsdict index eabdc3c32..788eb95fc 100644 --- a/Localization/StringsConvertor/input/si.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/si.lproj/Localizable.stringsdict @@ -15,7 +15,7 @@ one 1 unread notification other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds diff --git a/Localization/StringsConvertor/input/si.lproj/app.json b/Localization/StringsConvertor/input/si.lproj/app.json index a4542b9e9..364708892 100644 --- a/Localization/StringsConvertor/input/si.lproj/app.json +++ b/Localization/StringsConvertor/input/si.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Clean Cache", "message": "Successfully cleaned %s cache." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Create account", "see_more": "තව බලන්න", "preview": "පෙරදසුන", + "copy": "Copy", "share": "බෙදාගන්න", "share_user": "%s බෙදාගන්න", "share_post": "Share Post", @@ -91,12 +97,16 @@ "block_domain": "Block %s", "unblock_domain": "Unblock %s", "settings": "Settings", - "delete": "Delete" + "delete": "Delete", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Home", - "search": "Search", - "notification": "Notification", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", "profile": "Profile" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Sensitive Content", "media_content_warning": "Tap anywhere to reveal", "tap_to_reveal": "Tap to reveal", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "ඡන්දය", "closed": "වසා ඇත" @@ -153,6 +165,7 @@ "show_image": "Show image", "show_gif": "Show GIF", "show_video_player": "Show video player", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Add Row", "placeholder": { "label": "නම්පත", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bookmarks" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/sl.lproj/app.json b/Localization/StringsConvertor/input/sl.lproj/app.json index 0aed7bc15..3ce4e2daa 100644 --- a/Localization/StringsConvertor/input/sl.lproj/app.json +++ b/Localization/StringsConvertor/input/sl.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Počisti predpomnilnik", "message": "Uspešno počiščem predpomnilnik %s." + }, + "translation_failed": { + "title": "Opomba", + "message": "Prevod je spodletel. Morda skrbnik ni omogočil prevajanja na tem strežniku ali pa strežnik teče na starejši različici Masotodona, na kateri prevajanje še ni podprto.", + "button": "V redu" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Ustvari račun", "see_more": "Pokaži več", "preview": "Predogled", + "copy": "Kopiraj", "share": "Deli", "share_user": "Deli %s", "share_post": "Deli objavo", @@ -91,12 +97,16 @@ "block_domain": "Blokiraj %s", "unblock_domain": "Odblokiraj %s", "settings": "Nastavitve", - "delete": "Izbriši" + "delete": "Izbriši", + "translate_post": { + "title": "Prevedi iz: %s", + "unknown_language": "Neznano" + } }, "tabs": { "home": "Domov", - "search": "Iskanje", - "notification": "Obvestilo", + "search_and_explore": "Poišči in razišči", + "notifications": "Obvestila", "profile": "Profil" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Občutljiva vsebina", "media_content_warning": "Tapnite kamorkoli, da razkrijete", "tap_to_reveal": "Tapnite za razkritje", + "load_embed": "Naloži vdelano", + "link_via_user": "%s prek %s", "poll": { "vote": "Glasuj", "closed": "Zaprto" @@ -153,6 +165,7 @@ "show_image": "Pokaži sliko", "show_gif": "Pokaži GIF", "show_video_player": "Pokaži predvajalnik", + "share_link_in_post": "Deli povezavo v objavi", "tap_then_hold_to_show_menu": "Tapnite, nato držite, da se pojavi meni" }, "tag": { @@ -168,6 +181,12 @@ "private": "Samo sledilci osebe lahko vidijo to objavo.", "private_from_me": "Samo moji sledilci lahko vidijo to objavo.", "direct": "Samo omenjeni uporabnik lahko vidi to objavo." + }, + "translation": { + "translated_from": "Prevedeno iz %s s pomočjo %s", + "unknown_language": "Neznano", + "unknown_provider": "Neznano", + "show_original": "Pokaži izvirnik" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Vam sledi" }, "dashboard": { - "posts": "Objave", - "following": "sledi", - "followers": "sledilcev" + "my_posts": "objav", + "my_following": "sledi", + "my_followers": "sledilcev", + "other_posts": "objav", + "other_following": "sledi", + "other_followers": "sledilcev" }, "fields": { + "joined": "Pridružen_a", "add_row": "Dodaj vrstico", "placeholder": { "label": "Oznaka", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Zaznamki" + }, + "followed_tags": { + "title": "Sledene značke", + "header": { + "posts": "objav", + "participants": "udeležencev", + "posts_today": "objav danes" + }, + "actions": { + "follow": "Sledi", + "unfollow": "Prenehaj slediti" + } } } } diff --git a/Localization/StringsConvertor/input/sv.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/sv.lproj/Localizable.stringsdict index 3cbfeae6d..43a0ff8e4 100644 --- a/Localization/StringsConvertor/input/sv.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/sv.lproj/Localizable.stringsdict @@ -280,7 +280,7 @@ NSStringFormatValueTypeKey ld one - %ld år kvar + 1 år kvar other %ld år kvar @@ -296,7 +296,7 @@ NSStringFormatValueTypeKey ld one - %ld månad kvar + 1 månad kvar other %ld månader kvar @@ -312,7 +312,7 @@ NSStringFormatValueTypeKey ld one - %ld dag kvar + 1 dag kvar other %ld dagar kvar @@ -360,7 +360,7 @@ NSStringFormatValueTypeKey ld one - %ld sekund kvar + 1 sekund kvar other %ld sekunder kvar @@ -408,7 +408,7 @@ NSStringFormatValueTypeKey ld one - %ldd sedan + 1d sedan other %ldd sedan @@ -424,7 +424,7 @@ NSStringFormatValueTypeKey ld one - %ldt sedan + 1t sedan other %ldt sedan diff --git a/Localization/StringsConvertor/input/sv.lproj/app.json b/Localization/StringsConvertor/input/sv.lproj/app.json index 7951e1958..400758cd9 100644 --- a/Localization/StringsConvertor/input/sv.lproj/app.json +++ b/Localization/StringsConvertor/input/sv.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Rensa cache", "message": "Rensade %s cache." + }, + "translation_failed": { + "title": "Anteckning", + "message": "Översättningen misslyckades. Det kan hända att administratören inte har aktiverat översättningar på den här servern eller att servern kör en äldre version av Mastodon som inte har stöd för översättningar ännu.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Skapa konto", "see_more": "Visa mer", "preview": "Förhandsvisa", + "copy": "Kopiera", "share": "Dela", "share_user": "Dela %s", "share_post": "Dela inlägg", @@ -91,12 +97,16 @@ "block_domain": "Blockera %s", "unblock_domain": "Avblockera %s", "settings": "Inställningar", - "delete": "Radera" + "delete": "Radera", + "translate_post": { + "title": "Översätt från %s", + "unknown_language": "Okänt" + } }, "tabs": { "home": "Hem", - "search": "Sök", - "notification": "Notis", + "search_and_explore": "Sök och utforska", + "notifications": "Notiser", "profile": "Profil" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Känsligt innehåll", "media_content_warning": "Tryck var som helst för att visa", "tap_to_reveal": "Tryck för att visa", + "load_embed": "Ladda inbäddning", + "link_via_user": "%s via %s", "poll": { "vote": "Rösta", "closed": "Stängd" @@ -153,6 +165,7 @@ "show_image": "Visa bild", "show_gif": "Visa GIF", "show_video_player": "Visa videospelare", + "share_link_in_post": "Dela länk i inlägg", "tap_then_hold_to_show_menu": "Tryck och håll ned för att visa menyn" }, "tag": { @@ -168,6 +181,12 @@ "private": "Endast deras följare kan se detta inlägg.", "private_from_me": "Bara mina följare kan se det här inlägget.", "direct": "Endast omnämnda användare kan se detta inlägg." + }, + "translation": { + "translated_from": "Översatt från %s med %s", + "unknown_language": "Okänt", + "unknown_provider": "Okänd", + "show_original": "Visa original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "Följer dig" }, "dashboard": { - "posts": "inlägg", - "following": "följer", - "followers": "följare" + "my_posts": "inlägg", + "my_following": "följer", + "my_followers": "följare", + "other_posts": "inlägg", + "other_following": "följer", + "other_followers": "följare" }, "fields": { + "joined": "Gick med", "add_row": "Lägg till rad", "placeholder": { "label": "Etikett", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Bokmärken" + }, + "followed_tags": { + "title": "Följda hashtaggar", + "header": { + "posts": "inlägg", + "participants": "deltagare", + "posts_today": "inlägg idag" + }, + "actions": { + "follow": "Följ", + "unfollow": "Avfölj" + } } } } diff --git a/Localization/StringsConvertor/input/th.lproj/app.json b/Localization/StringsConvertor/input/th.lproj/app.json index 7b1a3d08e..6b3421d47 100644 --- a/Localization/StringsConvertor/input/th.lproj/app.json +++ b/Localization/StringsConvertor/input/th.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "ล้างแคช", "message": "ล้างแคช %s สำเร็จ" + }, + "translation_failed": { + "title": "หมายเหตุ", + "message": "การแปลล้มเหลว บางทีผู้ดูแลอาจไม่ได้เปิดใช้งานการแปลในเซิร์ฟเวอร์นี้หรือเซิร์ฟเวอร์นี้กำลังใช้ Mastodon รุ่นเก่ากว่าที่ยังไม่รองรับการแปล", + "button": "ตกลง" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "สร้างบัญชี", "see_more": "ดูเพิ่มเติม", "preview": "แสดงตัวอย่าง", + "copy": "คัดลอก", "share": "แบ่งปัน", "share_user": "แบ่งปัน %s", "share_post": "แบ่งปันโพสต์", @@ -91,12 +97,16 @@ "block_domain": "ปิดกั้น %s", "unblock_domain": "เลิกปิดกั้น %s", "settings": "การตั้งค่า", - "delete": "ลบ" + "delete": "ลบ", + "translate_post": { + "title": "แปลจาก %s", + "unknown_language": "ไม่รู้จัก" + } }, "tabs": { "home": "หน้าแรก", - "search": "ค้นหา", - "notification": "การแจ้งเตือน", + "search_and_explore": "ค้นหาและสำรวจ", + "notifications": "การแจ้งเตือน", "profile": "โปรไฟล์" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "เนื้อหาที่ละเอียดอ่อน", "media_content_warning": "แตะที่ใดก็ตามเพื่อเปิดเผย", "tap_to_reveal": "แตะเพื่อเปิดเผย", + "load_embed": "โหลดที่ฝังไว้", + "link_via_user": "%s ผ่าน %s", "poll": { "vote": "ลงคะแนน", "closed": "ปิดแล้ว" @@ -153,6 +165,7 @@ "show_image": "แสดงภาพ", "show_gif": "แสดง GIF", "show_video_player": "แสดงตัวเล่นวิดีโอ", + "share_link_in_post": "แบ่งปันลิงก์ในโพสต์", "tap_then_hold_to_show_menu": "แตะค้างไว้เพื่อแสดงเมนู" }, "tag": { @@ -168,6 +181,12 @@ "private": "เฉพาะผู้ติดตามของเขาเท่านั้นที่สามารถเห็นโพสต์นี้", "private_from_me": "เฉพาะผู้ติดตามของฉันเท่านั้นที่สามารถเห็นโพสต์นี้", "direct": "เฉพาะผู้ใช้ที่กล่าวถึงเท่านั้นที่สามารถเห็นโพสต์นี้" + }, + "translation": { + "translated_from": "แปลจาก %s โดยใช้ %s", + "unknown_language": "ไม่รู้จัก", + "unknown_provider": "ไม่รู้จัก", + "show_original": "แสดงดั้งเดิมอยู่" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "ติดตามคุณ" }, "dashboard": { - "posts": "โพสต์", - "following": "กำลังติดตาม", - "followers": "ผู้ติดตาม" + "my_posts": "โพสต์", + "my_following": "กำลังติดตาม", + "my_followers": "ผู้ติดตาม", + "other_posts": "โพสต์", + "other_following": "กำลังติดตาม", + "other_followers": "ผู้ติดตาม" }, "fields": { + "joined": "เข้าร่วมเมื่อ", "add_row": "เพิ่มแถว", "placeholder": { "label": "ป้ายชื่อ", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "ที่คั่นหน้า" + }, + "followed_tags": { + "title": "แท็กที่ติดตาม", + "header": { + "posts": "โพสต์", + "participants": "ผู้เข้าร่วม", + "posts_today": "โพสต์วันนี้" + }, + "actions": { + "follow": "ติดตาม", + "unfollow": "เลิกติดตาม" + } } } } diff --git a/Localization/StringsConvertor/input/tr.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/tr.lproj/Localizable.stringsdict index 6ef7f4c75..13552b607 100644 --- a/Localization/StringsConvertor/input/tr.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/tr.lproj/Localizable.stringsdict @@ -53,7 +53,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + %#@character_count@ kaldı character_count NSStringFormatSpecTypeKey @@ -61,9 +61,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 karakter other - %ld characters + %ld karakter plural.count.followed_by_and_mutual @@ -88,9 +88,9 @@ NSStringFormatValueTypeKey ld one - Followed by %1$@, and another mutual + %1$@ ve bir ortak kişi tarafından takip edildi other - Followed by %1$@, and %ld mutuals + %1$@ ve %ld ortak kişi tarafından takip edildi plural.count.metric_formatted.post @@ -120,9 +120,9 @@ NSStringFormatValueTypeKey ld one - 1 media + 1 medya other - %ld media + %ld medya plural.count.post diff --git a/Localization/StringsConvertor/input/tr.lproj/app.json b/Localization/StringsConvertor/input/tr.lproj/app.json index 37325cf05..c22c6a3f9 100644 --- a/Localization/StringsConvertor/input/tr.lproj/app.json +++ b/Localization/StringsConvertor/input/tr.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Önbelleği Temizle", "message": "%s boyutunda önbellek temizlendi." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -74,10 +79,11 @@ "take_photo": "Fotoğraf Çek", "save_photo": "Fotoğrafı Kaydet", "copy_photo": "Fotoğrafı Kopyala", - "sign_in": "Log in", - "sign_up": "Create account", + "sign_in": "Giriş Yap", + "sign_up": "Hesap oluştur", "see_more": "Daha Fazla Gör", "preview": "Önizleme", + "copy": "Copy", "share": "Paylaş", "share_user": "%s ile paylaş", "share_post": "Gönderiyi Paylaş", @@ -91,12 +97,16 @@ "block_domain": "%s kişisini engelle", "unblock_domain": "%s kişisinin engelini kaldır", "settings": "Ayarlar", - "delete": "Sil" + "delete": "Sil", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Ana Sayfa", - "search": "Arama", - "notification": "Bildirimler", + "search_and_explore": "Ara ve Keşfet", + "notifications": "Bildirimler", "profile": "Profil" }, "keyboard": { @@ -132,15 +142,17 @@ "sensitive_content": "Hassas İçerik", "media_content_warning": "Göstermek için herhangi bir yere basın", "tap_to_reveal": "Göstermek için basın", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Oy ver", "closed": "Kapandı" }, "meta_entity": { - "url": "Link: %s", - "hashtag": "Hashtag: %s", - "mention": "Show Profile: %s", - "email": "Email address: %s" + "url": "Bağlantı: %s", + "hashtag": "Etiket: %s", + "mention": "Profili Göster: %s", + "email": "E-posta adresi: %s" }, "actions": { "reply": "Yanıtla", @@ -153,6 +165,7 @@ "show_image": "Görüntüyü göster", "show_gif": "GIF'i göster", "show_video_player": "Video oynatıcıyı göster", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Menüyü göstermek için dokunun ve basılı tutun" }, "tag": { @@ -168,6 +181,12 @@ "private": "Sadece gönderi sahibinin takipçileri bu gönderiyi görebilir.", "private_from_me": "Sadece benim takipçilerim bu gönderiyi görebilir.", "direct": "Sadece bahsedilen kullanıcı bu gönderiyi görebilir." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -187,8 +206,8 @@ "unmute_user": "Sesini aç %s", "muted": "Susturuldu", "edit_info": "Bilgiyi Düzenle", - "show_reblogs": "Show Reblogs", - "hide_reblogs": "Hide Reblogs" + "show_reblogs": "Yeniden Paylaşımları Göster", + "hide_reblogs": "Yeniden Paylaşımları Gizle" }, "timeline": { "filtered": "Filtrelenmiş", @@ -219,15 +238,15 @@ "log_in": "Oturum Aç" }, "login": { - "title": "Welcome back", - "subtitle": "Log you in on the server you created your account on.", + "title": "Tekrar hoş geldin", + "subtitle": "Hesabını oluşturduğun sunucuya giriş yap.", "server_search_field": { - "placeholder": "Enter URL or search for your server" + "placeholder": "Bir URL girin ya da sunucunuzu arayın" } }, "server_picker": { "title": "Mastodon, farklı topluluklardaki kullanıcılardan oluşur.", - "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.", + "subtitle": "Bölgenize dayalı, ilginize dayalı ya da genel amaçlı bir sunucu seçin. Hangi sunucuda olduğunuz fark etmeksizin Mastodon'daki herkes ile konuşabilirsiniz.", "button": { "category": { "all": "Tümü", @@ -254,7 +273,7 @@ "category": "KATEGORİ" }, "input": { - "search_servers_or_enter_url": "Search communities or enter URL" + "search_servers_or_enter_url": "Topluluklar arayın ya da bir URL girin" }, "empty_state": { "finding_servers": "Mevcut sunucular aranıyor...", @@ -388,12 +407,12 @@ "attachment_broken": "Bu %s bozuk ve Mastodon'a\nyüklenemiyor.", "description_photo": "Görme engelliler için fotoğrafı tarif edin...", "description_video": "Görme engelliler için videoyu tarif edin...", - "load_failed": "Load Failed", - "upload_failed": "Upload Failed", - "can_not_recognize_this_media_attachment": "Can not recognize this media attachment", - "attachment_too_large": "Attachment too large", - "compressing_state": "Compressing...", - "server_processing_state": "Server Processing..." + "load_failed": "Yükleme Başarısız", + "upload_failed": "Yükleme Başarısız", + "can_not_recognize_this_media_attachment": "Ekteki medya uzantısı görüntülenemiyor", + "attachment_too_large": "Ek boyutu çok büyük", + "compressing_state": "Sıkıştırılıyor...", + "server_processing_state": "Sunucu İşliyor..." }, "poll": { "duration_time": "Süre: %s", @@ -404,7 +423,7 @@ "three_days": "3 Gün", "seven_days": "7 Gün", "option_number": "Seçenek %ld", - "the_poll_is_invalid": "The poll is invalid", + "the_poll_is_invalid": "Anket geçersiz", "the_poll_has_empty_option": "The poll has empty option" }, "content_warning": { @@ -427,8 +446,8 @@ "enable_content_warning": "İçerik Uyarısını Etkinleştir", "disable_content_warning": "İçerik Uyarısını Kapat", "post_visibility_menu": "Gönderi Görünürlüğü Menüsü", - "post_options": "Post Options", - "posting_as": "Posting as %s" + "post_options": "Gönderi Seçenekleri", + "posting_as": "%s olarak paylaşılıyor" }, "keyboard": { "discard_post": "Gönderiyi İptal Et", @@ -444,19 +463,23 @@ "follows_you": "Seni takip ediyor" }, "dashboard": { - "posts": "gönderiler", - "following": "takip ediliyor", - "followers": "takipçi" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Satır Ekle", "placeholder": { "label": "Etiket", "content": "İçerik" }, "verified": { - "short": "Verified on %s", - "long": "Ownership of this link was checked on %s" + "short": "%s tarafında onaylı", + "long": "%s adresinin sahipliği kontrol edilmiş" } }, "segmented_control": { @@ -484,12 +507,12 @@ "message": "%s engellemeyi kaldırmayı onaylayın" }, "confirm_show_reblogs": { - "title": "Show Reblogs", - "message": "Confirm to show reblogs" + "title": "Yeniden Paylaşımları Göster", + "message": "Yeniden paylaşımları göstermeyi onayla" }, "confirm_hide_reblogs": { - "title": "Hide Reblogs", - "message": "Confirm to hide reblogs" + "title": "Yeniden Paylaşımları Gizle", + "message": "Yeniden paylaşımları gizlemeyi onayla" } }, "accessibility": { @@ -508,8 +531,8 @@ "footer": "Diğer sunucudaki takip edilenler gösterilemiyor." }, "familiarFollowers": { - "title": "Followers you familiar", - "followed_by_names": "Followed by %s" + "title": "Tanıyor olabileceğin takipçiler", + "followed_by_names": "%s tarafından takip ediliyor" }, "favorited_by": { "title": "Favorited By" @@ -581,10 +604,10 @@ "show_mentions": "Bahsetmeleri Göster" }, "follow_request": { - "accept": "Accept", - "accepted": "Accepted", - "reject": "reject", - "rejected": "Rejected" + "accept": "Kabul Et", + "accepted": "Kabul Edildi", + "reject": "Reddet", + "rejected": "Reddedildi" } }, "thread": { @@ -669,9 +692,9 @@ "i_dont_like_it": "Beğenmedim", "it_is_not_something_you_want_to_see": "Görmek isteyeceğim bir şey değil", "its_spam": "Spam", - "malicious_links_fake_engagement_or_repetetive_replies": "Malicious links, fake engagement, or repetetive replies", + "malicious_links_fake_engagement_or_repetetive_replies": "Kötü niyetli bağlantılar, sahte etkileşim veya tekrarlayan yanıtlar", "it_violates_server_rules": "Sunucu kurallarını ihlal ediyor", - "you_are_aware_that_it_breaks_specific_rules": "You are aware that it breaks specific rules", + "you_are_aware_that_it_breaks_specific_rules": "Belirli kuralları ihlal ettiğinin farkındasınız", "its_something_else": "Başka bir şey", "the_issue_does_not_fit_into_other_categories": "Sorun bunlardan biri değil" }, @@ -692,15 +715,15 @@ }, "step_final": { "dont_want_to_see_this": "Bunu görmek istemiyor musunuz?", - "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", + "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "Mastodon'da beğenmediğiniz bir şey gördüğünüzde, o kişiyi deneyiminizden çıkarabilirsiniz.", "unfollow": "Takibi bırak", - "unfollowed": "Unfollowed", + "unfollowed": "Takipten çıkıldı", "unfollow_user": "Takipten çık %s", "mute_user": "Sustur %s", "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", - "block_user": "Block %s", - "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.", - "while_we_review_this_you_can_take_action_against_user": "While we review this, you can take action against %s" + "block_user": "%s kişisini engelle", + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "Artık sizi takip edemez ve gönderilerinizi göremezler ama engellendiklerini görebilirler.", + "while_we_review_this_you_can_take_action_against_user": "Biz bunu incelerken siz %s hesabına karşı önlem alabilirsiniz" } }, "preview": { @@ -721,7 +744,19 @@ "accessibility_hint": "Bu yardımı kapatmak için çift tıklayın" }, "bookmark": { - "title": "Bookmarks" + "title": "Yer İmleri" + }, + "followed_tags": { + "title": "Takip Edilen Etiketler", + "header": { + "posts": "gönderiler", + "participants": "katılımcılar", + "posts_today": "posts today" + }, + "actions": { + "follow": "Takip et", + "unfollow": "Takibi bırak" + } } } } diff --git a/Localization/StringsConvertor/input/uk.lproj/Localizable.stringsdict b/Localization/StringsConvertor/input/uk.lproj/Localizable.stringsdict index 32e4cf9aa..21681e1b9 100644 --- a/Localization/StringsConvertor/input/uk.lproj/Localizable.stringsdict +++ b/Localization/StringsConvertor/input/uk.lproj/Localizable.stringsdict @@ -13,19 +13,19 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 не прочитане сповіщення few - %ld unread notification + %ld не прочитаних сповіщень many - %ld unread notification + %ld не прочитаних сповіщень other - %ld unread notification + %ld не прочитаних сповіщень a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + Перевищено ліміт вводу на %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -33,19 +33,19 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 символ few - %ld characters + %ld символи many - %ld characters + %ld символів other - %ld characters + %ld символів a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + Залишається вхідний ліміт %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -53,19 +53,19 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 символ few - %ld characters + %ld символи many - %ld characters + %ld символів other - %ld characters + %ld символів a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + %#@character_count@ ліворуч character_count NSStringFormatSpecTypeKey @@ -73,13 +73,13 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 символ few - %ld characters + %ld символи many - %ld characters + %ld символів other - %ld characters + %ld символів plural.count.followed_by_and_mutual @@ -108,13 +108,13 @@ NSStringFormatValueTypeKey ld one - Followed by %1$@, and another mutual + Читають %1$@ та інші few - Followed by %1$@, and %ld mutuals + Читають %1$@, та %ld взаємних many - Followed by %1$@, and %ld mutuals + Читають %1$@, та %ld взаємних other - Followed by %1$@, and %ld mutuals + Читають %1$@, та %ld взаємних plural.count.metric_formatted.post @@ -128,13 +128,13 @@ NSStringFormatValueTypeKey ld one - post + допис few - posts + дописи many - posts + дописів other - posts + дописів plural.count.media @@ -148,13 +148,13 @@ NSStringFormatValueTypeKey ld one - 1 media + медіа few - %ld media + %ld медіа many - %ld media + %ld медіа other - %ld media + %ld медіа plural.count.post @@ -168,13 +168,13 @@ NSStringFormatValueTypeKey ld one - 1 post + 1 пост few - %ld posts + %ld пости many - %ld posts + %ld постів other - %ld posts + %ld постів plural.count.favorite @@ -188,13 +188,13 @@ NSStringFormatValueTypeKey ld one - 1 favorite + 1 улюблене few - %ld favorites + %ld улюблених many - %ld favorites + %ld улюблених other - %ld favorites + %ld улюблених plural.count.reblog @@ -208,13 +208,13 @@ NSStringFormatValueTypeKey ld one - 1 reblog + 1 репост few - %ld reblogs + %ld репости many - %ld reblogs + %ld репостів other - %ld reblogs + %ld репостів plural.count.reply @@ -228,13 +228,13 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 відповідь few - %ld replies + %ld відповіді many - %ld replies + %ld відповідей other - %ld replies + %ld відповідей plural.count.vote @@ -248,13 +248,13 @@ NSStringFormatValueTypeKey ld one - 1 vote + 1 голос few - %ld votes + %ld голоси many - %ld votes + %ld голосів other - %ld votes + %ld голосів plural.count.voter @@ -268,13 +268,13 @@ NSStringFormatValueTypeKey ld one - 1 voter + 1 учасник голосування few - %ld voters + %ld учасники голосування many - %ld voters + %ld учасників голосування other - %ld voters + %ld учасників голосування plural.people_talking @@ -288,13 +288,13 @@ NSStringFormatValueTypeKey ld one - 1 people talking + 1 людина говорить few - %ld people talking + %ld людей говорять many - %ld people talking + %ld людей говорять other - %ld people talking + %ld людей говорять plural.count.following @@ -308,13 +308,13 @@ NSStringFormatValueTypeKey ld one - 1 following + підписаний few - %ld following + Підписаний на %ld many - %ld following + Підписаний на %ld other - %ld following + Підписаний на %ld plural.count.follower @@ -328,13 +328,13 @@ NSStringFormatValueTypeKey ld one - 1 follower + 1 підписник few - %ld followers + %ld підписників many - %ld followers + %ld підписників other - %ld followers + %ld підписників date.year.left @@ -348,13 +348,13 @@ NSStringFormatValueTypeKey ld one - 1 year left + залишився 1 рік few - %ld years left + %ld років залишилося many - %ld years left + %ld років залишилося other - %ld years left + %ld років залишилося date.month.left @@ -368,13 +368,13 @@ NSStringFormatValueTypeKey ld one - 1 months left + 1 місяць залишився few - %ld months left + %ld місяців залишилося many - %ld months left + %ld місяців залишилося other - %ld months left + %ld місяців залишилося date.day.left @@ -388,13 +388,13 @@ NSStringFormatValueTypeKey ld one - 1 day left + Лишився 1 день few - %ld days left + %ld днів залишилося many - %ld days left + %ld днів залишилося other - %ld days left + %ld днів залишилося date.hour.left @@ -408,13 +408,13 @@ NSStringFormatValueTypeKey ld one - 1 hour left + Залишилася 1 година few - %ld hours left + %ld годин залишилося many - %ld hours left + %ld годин залишилося other - %ld hours left + %ld годин залишилося date.minute.left @@ -428,13 +428,13 @@ NSStringFormatValueTypeKey ld one - 1 minute left + Залишилась одна хвилина few - %ld minutes left + %ld хвилин залишилося many - %ld minutes left + %ld хвилин залишилося other - %ld minutes left + %ld хвилин залишилося date.second.left @@ -448,13 +448,13 @@ NSStringFormatValueTypeKey ld one - 1 second left + Залишилась одна секунда few - %ld seconds left + %ld секунд залишилося many - %ld seconds left + %ld секунд залишилося other - %ld seconds left + %ld секунд залишилося date.year.ago.abbr @@ -468,13 +468,13 @@ NSStringFormatValueTypeKey ld one - 1y ago + 1 рік тому few - %ldy ago + %ld роки тому many - %ldy ago + %ld років тому other - %ldy ago + %ld років тому date.month.ago.abbr @@ -488,13 +488,13 @@ NSStringFormatValueTypeKey ld one - 1M ago + 1 місяць тому few - %ldM ago + %ld місяці тому many - %ldM ago + %ld місяців тому other - %ldM ago + %ld Місяців тому date.day.ago.abbr @@ -508,13 +508,13 @@ NSStringFormatValueTypeKey ld one - 1d ago + 1 день тому few - %ldd ago + %ld дня тому many - %ldd ago + %ld днів тому other - %ldd ago + %ld днів тому date.hour.ago.abbr @@ -528,13 +528,13 @@ NSStringFormatValueTypeKey ld one - 1h ago + 1 годину тому few - %ldh ago + %ld години тому many - %ldh ago + %ld годин тому other - %ldh ago + %ld годин тому date.minute.ago.abbr @@ -548,13 +548,13 @@ NSStringFormatValueTypeKey ld one - 1m ago + 1 хвилину тому few - %ldm ago + %ld хвилини тому many - %ldm ago + %ld хвилин тому other - %ldm ago + %ld хвилин тому date.second.ago.abbr @@ -568,13 +568,13 @@ NSStringFormatValueTypeKey ld one - 1s ago + 1 секунду тому few - %lds ago + %ld секунди тому many - %lds ago + %ld секунд тому other - %lds ago + %ld секунд тому diff --git a/Localization/StringsConvertor/input/uk.lproj/app.json b/Localization/StringsConvertor/input/uk.lproj/app.json index 3113ada74..230d61f7c 100644 --- a/Localization/StringsConvertor/input/uk.lproj/app.json +++ b/Localization/StringsConvertor/input/uk.lproj/app.json @@ -2,726 +2,761 @@ "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" + "title": "Помилка реєстрації" }, "server_error": { - "title": "Server Error" + "title": "Помилка сервера" }, "vote_failure": { - "title": "Vote Failure", - "poll_ended": "The poll has ended" + "title": "Помилка голосування", + "poll_ended": "Опитування завершено" }, "discard_post_content": { - "title": "Discard Draft", - "message": "Confirm to discard composed post content." + "title": "Видалити чернетку", + "message": "Підтвердьте, щоб відхилити створений вміст публікації." }, "publish_post_failure": { - "title": "Publish Failure", - "message": "Failed to publish the post.\nPlease check your internet connection.", + "title": "Помилка публікації", + "message": "Не вдалося опублікувати допис.\nПеревірте підключення до Інтернету.", "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": "Не можна додати відео до допису з зображенням.", + "more_than_one_video": "Не можна додати більше ніж 1 відео." } }, "edit_profile_failure": { - "title": "Edit Profile Error", - "message": "Cannot edit profile. Please try again." + "title": "Помилка редагування профілю", + "message": "Не вдалося редагувати профіль. Будь ласка, спробуйте ще раз." }, "sign_out": { - "title": "Sign Out", - "message": "Are you sure you want to sign out?", - "confirm": "Sign Out" + "title": "Вийти", + "message": "Ви справді бажаєте вийти?", + "confirm": "Вийти" }, "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": "Ви точно, точно впевнені, що хочете заблокувати весь домен %s? У більшості випадків для нормальної роботи краще заблокувати або приховати лише деяких користувачів. Ви не зможете бачити контент з цього домену у будь-яких стрічках або ваших сповіщеннях. Ваші підписники з цього домену будуть відписані від вас.", + "block_entire_domain": "Заблокувати домен" }, "save_photo_failure": { - "title": "Save Photo Failure", - "message": "Please enable the photo library access permission to save the photo." + "title": "Помилка збереження фото", + "message": "Будь ласка, увімкніть доступ до фотобібліотеки для збереження фотографій." }, "delete_post": { - "title": "Delete Post", - "message": "Are you sure you want to delete this post?" + "title": "Видалити допис", + "message": "Ви дійсно бажаєте видалити цей допис?" }, "clean_cache": { - "title": "Clean Cache", - "message": "Successfully cleaned %s cache." + "title": "Очистити кеш", + "message": "%s успішно очищено." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { "actions": { - "back": "Back", - "next": "Next", - "previous": "Previous", - "open": "Open", - "add": "Add", - "remove": "Remove", - "edit": "Edit", - "save": "Save", + "back": "Назад", + "next": "Далі", + "previous": "Попередній", + "open": "Відкрити", + "add": "Додати", + "remove": "Видалити", + "edit": "Редагувати", + "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": "Log in", - "sign_up": "Create account", - "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" + "done": "Готово", + "confirm": "Підтвердити", + "continue": "Далі", + "compose": "Створити", + "cancel": "Скасувати", + "discard": "Відхилити", + "try_again": "Спробувати ще раз", + "take_photo": "Зробити фото", + "save_photo": "Зберегти фото", + "copy_photo": "Копіювати фото", + "sign_in": "Увійти", + "sign_up": "Створити обліковий запис", + "see_more": "Дивіться більше", + "preview": "Попередній перегляд", + "copy": "Copy", + "share": "Поділитись", + "share_user": "Поділитися %s", + "share_post": "Поділитися записом", + "open_in_safari": "Відкрити у Safari", + "open_in_browser": "Відкрити в браузері", + "find_people": "Знайти людей, аби підписатися", + "manually_search": "Натомість шукати вручну", + "skip": "Пропустити", + "reply": "Відповісти", + "report_user": "Поскаржитись на %s", + "block_domain": "Блокувати %s", + "unblock_domain": "Розблокувати %s", + "settings": "Налаштування", + "delete": "Видалити", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { - "home": "Home", - "search": "Search", - "notification": "Notification", - "profile": "Profile" + "home": "Головна", + "search_and_explore": "Search and Explore", + "notifications": "Notifications", + "profile": "Профіль" }, "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": "Перейти до користувача %s", + "compose_new_post": "Написати новий допис", + "show_favorites": "Показати вибрані", + "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" + "previous_status": "Попередній допис", + "next_status": "Новий допис", + "open_status": "Відкрити допис", + "open_author_profile": "Відкрити профіль автора", + "open_reblogger_profile": "Відкрити профіль реблогера", + "reply_status": "Відповісти на допис", + "toggle_reblog": "Додати/прибрати Реблог", + "toggle_favorite": "Додати/прибрати з Обраного", + "toggle_content_warning": "Додати/прибрати попередження про вміст для дорослих", + "preview_image": "Попередній перегляд" }, "segmented_control": { - "previous_section": "Previous Section", - "next_section": "Next Section" + "previous_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", - "sensitive_content": "Sensitive Content", - "media_content_warning": "Tap anywhere to reveal", - "tap_to_reveal": "Tap to reveal", + "user_reblogged": "%s Зробив репост", + "user_replied_to": "Відповів %s", + "show_post": "Показати дописи", + "show_user_profile": "Показати профіль користувача", + "content_warning": "Попередження про вміст", + "sensitive_content": "Контент 18+", + "media_content_warning": "Натисніть будь-де, щоб показати більше", + "tap_to_reveal": "Натисніть, щоб відобразити", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { - "vote": "Vote", - "closed": "Closed" + "vote": "Проголосувати", + "closed": "Зачинено" }, "meta_entity": { - "url": "Link: %s", - "hashtag": "Hashtag: %s", - "mention": "Show Profile: %s", - "email": "Email address: %s" + "url": "Посилання: %s", + "hashtag": "Гештег: %s", + "mention": "Показати профіль: %s", + "email": "Електронна адреса: %s" }, "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" + "reply": "Відповісти", + "reblog": "Репост", + "unreblog": "Скасувати репост", + "favorite": "Улюблене", + "unfavorite": "Вилучити з улюбленого", + "menu": "Меню", + "hide": "Сховати", + "show_image": "Показати зображення", + "show_gif": "Показати GIF", + "show_video_player": "Показати відеоплеєр", + "share_link_in_post": "Share Link in Post", + "tap_then_hold_to_show_menu": "Натисніть та утримуйте, щоб показати меню" }, "tag": { - "url": "URL", - "mention": "Mention", - "link": "Link", - "hashtag": "Hashtag", - "email": "Email", - "emoji": "Emoji" + "url": "Адреса URL", + "mention": "Згадати", + "link": "Посилання", + "hashtag": "Гештег", + "email": "Електронна пошта", + "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": "Хто завгодно може бачити цей допис, але його не буде відображено у публічній стрічці.", + "private": "Лише їхні підписники можуть бачити цю публікацію.", + "private_from_me": "Тільки мої підписники можуть бачити цю публікацію.", + "direct": "Тільки згаданий користувач може бачити цю публікацію." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "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", - "show_reblogs": "Show Reblogs", - "hide_reblogs": "Hide Reblogs" + "follow": "Підписатися", + "following": "Підписаний", + "request": "Запит", + "pending": "Очікується", + "block": "Заблокувати", + "block_user": "Блокувати %s", + "block_domain": "Блокувати %s", + "unblock": "Розблокувати", + "unblock_user": "Розблокувати %s", + "blocked": "Заблоковано", + "mute": "Заглушити", + "mute_user": "Заглушити %s", + "unmute": "Сповіщати", + "unmute_user": "Сповіщати %s", + "muted": "Зам'ютити", + "edit_info": "Редагувати інформацію", + "show_reblogs": "Показати реблоги", + "hide_reblogs": "Сховати реблоги" }, "timeline": { - "filtered": "Filtered", + "filtered": "Відфільтровано", "timestamp": { - "now": "Now" + "now": "Щойно" }, "loader": { - "load_missing_posts": "Load missing posts", - "loading_missing_posts": "Loading missing posts...", - "show_more_replies": "Show more replies" + "load_missing_posts": "Завантажити пропущені дописи", + "loading_missing_posts": "Завантаження пропущених дописів...", + "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." + "no_status_found": "Публікацій не знайдено", + "blocking_warning": "Ви не можете переглянути профіль цього користувача, поки ви не розблокуєте їх.\nВаш профіль виглядає так.", + "user_blocking_warning": "Ви не можете переглядати профіль %s, поки ви не розблокуєте їх.\nВони бачать ваш профіль так.", + "blocked_warning": "Ви не можете переглянути профіль цього користувача, поки вони не розблокують вас.", + "user_blocked_warning": "Ви не можете переглянути профіль %s, поки він не розблокує вас.", + "suspended_warning": "Цього користувача було заблоковано.", + "user_suspended_warning": "Обліковий запис %s заблоковано." } } } }, "scene": { "welcome": { - "slogan": "Social networking\nback in your hands.", - "get_started": "Get Started", - "log_in": "Log In" + "slogan": "Соціальна мережа під вашим контролем.", + "get_started": "Почати", + "log_in": "Увійти" }, "login": { - "title": "Welcome back", - "subtitle": "Log you in on the server you created your account on.", + "title": "З поверненням", + "subtitle": "Увійдіть на сервері, де ви створили свій обліковий запис.", "server_search_field": { - "placeholder": "Enter URL or search for your server" + "placeholder": "Введіть URL-адресу або адресу сервера" } }, "server_picker": { - "title": "Mastodon is made of users in different servers.", - "subtitle": "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers.", + "title": "Mastodon складається з користувачів на різних серверах.", + "subtitle": "Оберіть сервер згідно з вашим регіоном, інтересами чи цілями. Ви можете спілкуватися з будь-ким на Mastodon, незалежно від обраних серверів.", "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" + "all": "Всі", + "all_accessiblity_description": "Категорія: Усі", + "academia": "академія", + "activism": "активізм", + "food": "їжа", + "furry": "фурі", + "games": "ігри", + "general": "загальне", + "journalism": "журналістика", + "lgbt": "лгбт", + "regional": "регіональний", + "art": "мистецтво", + "music": "музика", + "tech": "технології" }, - "see_less": "See Less", - "see_more": "See More" + "see_less": "Згорнути", + "see_more": "Показати більше" }, "label": { - "language": "LANGUAGE", - "users": "USERS", - "category": "CATEGORY" + "language": "МОВА", + "users": "КОРИСТУВАЧІ", + "category": "КАТЕГОРІЯ" }, "input": { - "search_servers_or_enter_url": "Search communities or enter URL" + "search_servers_or_enter_url": "Знайти спільноти, або ввести URL" }, "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": "Пошук доступних серверів...", + "bad_network": "Сталася помилка під час завантаження даних. Перевірте підключення до Інтернету.", + "no_results": "Жодних результатів" } }, "register": { - "title": "Let’s get you set up on %s", - "lets_get_you_set_up_on_domain": "Let’s get you set up on %s", + "title": "Налаштуймо Вас на %s", + "lets_get_you_set_up_on_domain": "Налаштуймо Вас на %s", "input": { "avatar": { - "delete": "Delete" + "delete": "Видалити" }, "username": { - "placeholder": "username", - "duplicate_prompt": "This username is taken." + "placeholder": "ім'я користувача", + "duplicate_prompt": "Це ім'я користувача вже зайняте." }, "display_name": { - "placeholder": "display name" + "placeholder": "видиме ім'я" }, "email": { - "placeholder": "email" + "placeholder": "електронна пошта" }, "password": { - "placeholder": "password", - "require": "Your password needs at least:", - "character_limit": "8 characters", + "placeholder": "пароль", + "require": "Ваш пароль повинен містити як мінімум:", + "character_limit": "8 символів", "accessibility": { - "checked": "checked", - "unchecked": "unchecked" + "checked": "встановлено", + "unchecked": "знято позначку" }, - "hint": "Your password needs at least eight characters" + "hint": "Ваш пароль повинен містити принаймні вісім символів" }, "invite": { - "registration_user_invite_request": "Why do you want to join?" + "registration_user_invite_request": "Чому ви хочете приєднатися?" } }, "error": { "item": { - "username": "Username", - "email": "Email", - "password": "Password", - "agreement": "Agreement", - "locale": "Locale", - "reason": "Reason" + "username": "Ім'я користувача", + "email": "Електронна пошта", + "password": "Пароль", + "agreement": "Угода", + "locale": "Локаль", + "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" + "blocked": "%s містить заборонених провайдерів email", + "unreachable": "%s здається, не існує", + "taken": "%s вже використовується", + "reserved": "%s є зарезервованим ключовим словом", + "accepted": "%s має бути прийнято", + "blank": "%s необхідно", + "invalid": "%s є недійсним", + "too_long": "%s занадто довгий", + "too_short": "%s є закоротким", + "inclusion": "%s не є підтримуваним значенням" }, "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": "Ім'я користувача повинно містити лише літери, цифрові символи та знак підкреслення", + "username_too_long": "Ім'я користувача занадто довге (не може бути більше 30 символів)", + "email_invalid": "Це не дійсна адреса електронної пошти", + "password_too_short": "Пароль закороткий (має містити мінімум 8 символів)" } } }, "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": "Деякі основні правила.", + "subtitle": "Ці призначені для модераторів - %s.", + "prompt": "Продовжуючи, ви піддаєтеся умовам надання послуг та політики конфіденційності для хвороби %s.", + "terms_of_service": "умови використання", + "privacy_policy": "політика конфіденційності", "button": { - "confirm": "I Agree" + "confirm": "Я погоджуюся" } }, "confirm_email": { - "title": "One last thing.", - "subtitle": "Tap the link we emailed to you to verify your account.", - "tap_the_link_we_emailed_to_you_to_verify_your_account": "Tap the link we emailed to you to verify your account", + "title": "Остання річ.", + "subtitle": "Натисніть на посилання, яке ми надіслали на вашу пошту, щоб підтвердити свій обліковий запис.", + "tap_the_link_we_emailed_to_you_to_verify_your_account": "Натисніть на посилання, яке ми надіслали на вашу пошту, щоб підтвердити свій обліковий запис", "button": { - "open_email_app": "Open Email App", - "resend": "Resend" + "open_email_app": "Відкрити додаток Електронної пошти", + "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" + "title": "Перевірте свою електронну пошту", + "description": "Перевірте правильність адреси електронної пошти, а також теку зі спамом, якщо ви ще не зробили цього.", + "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" + "title": "Перевірте вашу поштову скриньку.", + "description": "Ми щойно надіслали вам електронного листа. Перевірте вашу спам теку, якщо ви не зробили цього.", + "mail": "Пошта", + "open_email_client": "Відкрити поштового клієнта" } }, "home_timeline": { - "title": "Home", + "title": "Головна", "navigation_bar_state": { - "offline": "Offline", - "new_posts": "See new posts", - "published": "Published!", - "Publishing": "Publishing post...", + "offline": "В автономному режимі", + "new_posts": "До нових дописів", + "published": "Опубліковано!", + "Publishing": "Допис публікується...", "accessibility": { - "logo_label": "Logo Button", - "logo_hint": "Tap to scroll to top and tap again to previous location" + "logo_label": "Кнопка Логотипу", + "logo_hint": "Торкніться для прокручування вгору і натисніть ще раз на попереднє розташування" } } }, "suggestion_account": { - "title": "Find People to Follow", - "follow_explain": "When you follow someone, you’ll see their posts in your home feed." + "title": "Знайти людей, аби підписатися", + "follow_explain": "Коли ви підпишетесь на когось, ви побачите його дописи у своїй домашній стрічці." }, "compose": { "title": { - "new_post": "New Post", - "new_reply": "New Reply" + "new_post": "Новий допис", + "new_reply": "Нова відповідь" }, "media_selection": { - "camera": "Take Photo", - "photo_library": "Photo Library", - "browse": "Browse" + "camera": "Зробити фото", + "photo_library": "Галерея", + "browse": "Огляд" }, - "content_input_placeholder": "Type or paste what’s on your mind", - "compose_action": "Publish", - "replying_to_user": "replying to %s", + "content_input_placeholder": "Що у Вас на думці", + "compose_action": "Опублікувати", + "replying_to_user": "відповідь на: %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...", - "load_failed": "Load Failed", - "upload_failed": "Upload Failed", - "can_not_recognize_this_media_attachment": "Can not recognize this media attachment", - "attachment_too_large": "Attachment too large", - "compressing_state": "Compressing...", - "server_processing_state": "Server Processing..." + "photo": "фото", + "video": "відео", + "attachment_broken": "Цей %s пошкоджений і не може бути\nзавантажений в Mastodon.", + "description_photo": "Опишіть фото для людей з вадами зору...", + "description_video": "Опишіть відео для людей з вадами зору...", + "load_failed": "Не вдалося завантажити", + "upload_failed": "Не вдалося завантажити", + "can_not_recognize_this_media_attachment": "Неможливо розпізнати цей медіафайл", + "attachment_too_large": "Вкладення завелике", + "compressing_state": "Стиснення...", + "server_processing_state": "Обробка сервера..." }, "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", - "the_poll_is_invalid": "The poll is invalid", - "the_poll_has_empty_option": "The poll has empty option" + "duration_time": "Тривалість: %s", + "thirty_minutes": "30 хвилин", + "one_hour": "1 Година", + "six_hours": "6 Годин", + "one_day": "1 День", + "three_days": "3 Дні", + "seven_days": "7 Днів", + "option_number": "Параметр %ld", + "the_poll_is_invalid": "Неприпустимий варіант опитування", + "the_poll_has_empty_option": "В опитуванні є порожній варіант" }, "content_warning": { - "placeholder": "Write an accurate warning here..." + "placeholder": "Напишіть своє попередження тут..." }, "visibility": { - "public": "Public", - "unlisted": "Unlisted", - "private": "Followers only", - "direct": "Only people I mention" + "public": "Публічно", + "unlisted": "Приховувати зі стрічок", + "private": "Тільки для підписників", + "direct": "Тільки людям, яких я згадав" }, "auto_complete": { - "space_to_add": "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", - "post_options": "Post Options", - "posting_as": "Posting as %s" + "append_attachment": "Додати вкладення", + "append_poll": "Додати опитування", + "remove_poll": "Видалити опитування", + "custom_emoji_picker": "Вибір власних емодзі", + "enable_content_warning": "Увімкнути попередження про контент", + "disable_content_warning": "Вимкнути попередження про контент", + "post_visibility_menu": "Меню видимості поста", + "post_options": "Параметри повідомлення", + "posting_as": "Опублікувати як %s" }, "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": "Відхилити допис", + "publish_post": "Опублікувати повідомлення", + "toggle_poll": "Відкрити або закрити опитування", + "toggle_content_warning": "Попередження про вміст", + "append_attachment_entry": "Додати вкладення - %s", + "select_visibility_entry": "Оберіть видимість - %s" } }, "profile": { "header": { - "follows_you": "Follows You" + "follows_you": "Підписаний(-на) на вас" }, "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { - "add_row": "Add Row", + "joined": "Joined", + "add_row": "Додати рядок", "placeholder": { - "label": "Label", - "content": "Content" + "label": "Позначка", + "content": "Зміст" }, "verified": { - "short": "Verified on %s", - "long": "Ownership of this link was checked on %s" + "short": "Перевірено %s", + "long": "Права власності на це посилання були перевірені %s" } }, "segmented_control": { - "posts": "Posts", - "replies": "Replies", - "posts_and_replies": "Posts and Replies", - "media": "Media", - "about": "About" + "posts": "Дописи", + "replies": "Відповіді", + "posts_and_replies": "Дописи й відповіді", + "media": "Медіа", + "about": "Про застосунок" }, "relationship_action_alert": { "confirm_mute_user": { - "title": "Mute Account", - "message": "Confirm to mute %s" + "title": "Заглушити обліковий запис", + "message": "Підтвердити заглушення %s" }, "confirm_unmute_user": { - "title": "Unmute Account", - "message": "Confirm to unmute %s" + "title": "Розглушити обліковий запис", + "message": "Підтвердить розглушення %s" }, "confirm_block_user": { - "title": "Block Account", - "message": "Confirm to block %s" + "title": "Заблокувати обліковий запис", + "message": "Підтвердити блокування %s" }, "confirm_unblock_user": { - "title": "Unblock Account", - "message": "Confirm to unblock %s" + "title": "Розблокувати обліковий запис", + "message": "Підтвердити розблокування %s" }, "confirm_show_reblogs": { - "title": "Show Reblogs", - "message": "Confirm to show reblogs" + "title": "Показати реблоги", + "message": "Підтвердити показ реблогів" }, "confirm_hide_reblogs": { - "title": "Hide Reblogs", - "message": "Confirm to hide reblogs" + "title": "Сховати реблоги", + "message": "Підтвердити, щоб приховати реблоги" } }, "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": { - "title": "follower", - "footer": "Followers from other servers are not displayed." + "title": "підписник", + "footer": "Підписники з інших серверів не відображаються." }, "following": { - "title": "following", - "footer": "Follows from other servers are not displayed." + "title": "підписаний", + "footer": "Підписки з інших серверів не відображаються." }, "familiarFollowers": { - "title": "Followers you familiar", - "followed_by_names": "Followed by %s" + "title": "Підписники, яких ви знаєте", + "followed_by_names": "Має серед підписників %s" }, "favorited_by": { - "title": "Favorited By" + "title": "Є в обраних у" }, "reblogged_by": { - "title": "Reblogged By" + "title": "Репостнуто" }, "search": { - "title": "Search", + "title": "Пошук", "search_bar": { - "placeholder": "Search hashtags and users", - "cancel": "Cancel" + "placeholder": "Пошук за гештегами та користувачами", + "cancel": "Скасувати" }, "recommend": { - "button_text": "See All", + "button_text": "Переглянути всі", "hash_tag": { - "title": "Trending on Mastodon", - "description": "Hashtags that are getting quite a bit of attention", - "people_talking": "%s people are talking" + "title": "У Трендах на Мастодоні", + "description": "Гештеги, що привертають увагу", + "people_talking": "%s людей говорять" }, "accounts": { - "title": "Accounts you might like", - "description": "You may like to follow these accounts", - "follow": "Follow" + "title": "Акавнти, що можуть вам сподобатися", + "description": "Ви можете зацікавитися цими обліковими записами", + "follow": "Підписатися" } }, "searching": { "segment": { - "all": "All", - "people": "People", - "hashtags": "Hashtags", - "posts": "Posts" + "all": "Всі", + "people": "Громада", + "hashtags": "Гештеги", + "posts": "Дописи" }, "empty_state": { - "no_results": "No results" + "no_results": "Жодних результатів" }, - "recent_search": "Recent searches", - "clear": "Clear" + "recent_search": "Нещодавні запити", + "clear": "Очистити" } }, "discovery": { "tabs": { - "posts": "Posts", - "hashtags": "Hashtags", - "news": "News", - "community": "Community", - "for_you": "For You" + "posts": "Дописи", + "hashtags": "Гештеги", + "news": "Новини", + "community": "Спільнота", + "for_you": "Для Вас" }, - "intro": "These are the posts gaining traction in your corner of Mastodon." + "intro": "Ось найбільш популярні дописи серед вашого серверу Mastodon." }, "favorite": { - "title": "Your Favorites" + "title": "Ваші Вподобання" }, "notification": { "title": { - "Everything": "Everything", - "Mentions": "Mentions" + "Everything": "Все", + "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" + "followed_you": "підписався(-лась) на вас", + "favorited_your_post": "вподобав(-ла) ваш допис", + "reblogged_your_post": "поширив(-ла) ваш допис", + "mentioned_you": "згадав(-ла) вас", + "request_to_follow_you": "запит на підписку", + "poll_has_ended": "опитування завершено" }, "keyobard": { - "show_everything": "Show Everything", - "show_mentions": "Show Mentions" + "show_everything": "Показати все", + "show_mentions": "Показати Згадки" }, "follow_request": { - "accept": "Accept", - "accepted": "Accepted", - "reject": "reject", - "rejected": "Rejected" + "accept": "Прийняти", + "accepted": "Прийнято", + "reject": "відхилити", + "rejected": "Відхилено" } }, "thread": { - "back_title": "Post", - "title": "Post from %s" + "back_title": "Допис", + "title": "Публікація від %s" }, "settings": { - "title": "Settings", + "title": "Налаштування", "section": { "appearance": { - "title": "Appearance", - "automatic": "Automatic", - "light": "Always Light", - "dark": "Always Dark" + "title": "Оформлення", + "automatic": "Автоматичне", + "light": "Завжди світле", + "dark": "Завжди темне" }, "look_and_feel": { - "title": "Look and Feel", - "use_system": "Use System", - "really_dark": "Really Dark", - "sorta_dark": "Sorta Dark", - "light": "Light" + "title": "Зовнішній вид", + "use_system": "Використати системний", + "really_dark": "Дуже темний", + "sorta_dark": "Трішкий темний", + "light": "Світлий" }, "notifications": { - "title": "Notifications", - "favorites": "Favorites my post", - "follows": "Follows me", - "boosts": "Reblogs my post", - "mentions": "Mentions me", + "title": "Сповіщення", + "favorites": "Вподобав ваш допис", + "follows": "Підписався на мене", + "boosts": "Реблог мого посту", + "mentions": "Згадує мене", "trigger": { - "anyone": "anyone", - "follower": "a follower", - "follow": "anyone I follow", - "noone": "no one", - "title": "Notify me when" + "anyone": "усі", + "follower": "підписник", + "follow": "хтось, за ким я слідкую", + "noone": "ніхто", + "title": "Повідомити мене, коли" } }, "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": "Налаштування", + "true_black_dark_mode": "Чорний режим", + "disable_avatar_animation": "Вимкнути анімовані аватари", + "disable_emoji_animation": "Вимкнути анімовані емодзі", + "using_default_browser": "Використовувати браузер за замовчуванням, щоб відкрити посилання", + "open_links_in_mastodon": "Відкривати посилання в Mastodon" }, "boring_zone": { - "title": "The Boring Zone", - "account_settings": "Account Settings", - "terms": "Terms of Service", - "privacy": "Privacy Policy" + "title": "Нудна зона", + "account_settings": "Налаштування облікового запису", + "terms": "Умови використання", + "privacy": "Політика конфіденційності" }, "spicy_zone": { - "title": "The Spicy Zone", - "clear": "Clear Media Cache", - "signout": "Sign Out" + "title": "Гостра зона", + "clear": "Очистити кеш медіа", + "signout": "Вийти" } }, "footer": { - "mastodon_description": "Mastodon is open source software. You can report issues on GitHub at %s (%s)" + "mastodon_description": "Mastodon — програма з відкритим вихідним кодом. Ви можете повідомити про проблеми на GitHub на %s (%s)" }, "keyboard": { - "close_settings_window": "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", + "title_report": "Скарга", + "title": "Поскаржитись на %s", + "step1": "Крок 1 з 2", + "step2": "Крок 2 з 2", + "content1": "Чи є інші дописи, які Ви хотіли б додати до скарги?", + "content2": "Чи є що-небудь модератори повинні знати про цю скаргу?", + "report_sent_title": "Дякуємо за скаргу, ми розглянемо її.", + "send": "Надіслати скаргу", + "skip_to_send": "Надіслати без коментаря", + "text_placeholder": "Введіть або вставте додаткові коментарі", + "reported": "Мої скарги", "step_one": { - "step_1_of_4": "Step 1 of 4", - "whats_wrong_with_this_post": "What's wrong with this post?", - "whats_wrong_with_this_account": "What's wrong with this account?", - "whats_wrong_with_this_username": "What's wrong with %s?", - "select_the_best_match": "Select the best match", - "i_dont_like_it": "I don’t like it", - "it_is_not_something_you_want_to_see": "It is not something you want to see", - "its_spam": "It’s spam", - "malicious_links_fake_engagement_or_repetetive_replies": "Malicious links, fake engagement, or repetetive replies", - "it_violates_server_rules": "It violates server rules", - "you_are_aware_that_it_breaks_specific_rules": "You are aware that it breaks specific rules", - "its_something_else": "It’s something else", - "the_issue_does_not_fit_into_other_categories": "The issue does not fit into other categories" + "step_1_of_4": "Крок 1 з 4", + "whats_wrong_with_this_post": "Що не так з цим постом?", + "whats_wrong_with_this_account": "Що не так з цим обліковим записом?", + "whats_wrong_with_this_username": "Що з %s не так?", + "select_the_best_match": "Оберіть найвідповідніший збіг", + "i_dont_like_it": "Мені це не подобається", + "it_is_not_something_you_want_to_see": "Це не те, що ви хотіли б побачити", + "its_spam": "Це спам", + "malicious_links_fake_engagement_or_repetetive_replies": "Підозрілі посилання, фейкові розмови або відповіді", + "it_violates_server_rules": "Це порушує правила сервера", + "you_are_aware_that_it_breaks_specific_rules": "Ви впевнені, що це порушує певні правила", + "its_something_else": "Це щось інше", + "the_issue_does_not_fit_into_other_categories": "Ця проблема не відповідає жодній іншій категорії" }, "step_two": { - "step_2_of_4": "Step 2 of 4", - "which_rules_are_being_violated": "Which rules are being violated?", - "select_all_that_apply": "Select all that apply", - "i_just_don’t_like_it": "I just don’t like it" + "step_2_of_4": "Крок 2 з 4", + "which_rules_are_being_violated": "Які правила порушено?", + "select_all_that_apply": "Виберіть усі варіанти, що підходять", + "i_just_don’t_like_it": "Мені це не подобається" }, "step_three": { - "step_3_of_4": "Step 3 of 4", - "are_there_any_posts_that_back_up_this_report": "Are there any posts that back up this report?", - "select_all_that_apply": "Select all that apply" + "step_3_of_4": "Крок 3 з 4", + "are_there_any_posts_that_back_up_this_report": "Чи є публікації, які підтверджують цю скаргу?", + "select_all_that_apply": "Виберіть усі варіанти, що підходять" }, "step_four": { - "step_4_of_4": "Step 4 of 4", - "is_there_anything_else_we_should_know": "Is there anything else we should know?" + "step_4_of_4": "Крок 4 з 4", + "is_there_anything_else_we_should_know": "Чи є ще щось, що ми повинні знати?" }, "step_final": { - "dont_want_to_see_this": "Don’t want to see this?", - "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", - "unfollow": "Unfollow", - "unfollowed": "Unfollowed", - "unfollow_user": "Unfollow %s", - "mute_user": "Mute %s", - "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", - "block_user": "Block %s", - "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.", - "while_we_review_this_you_can_take_action_against_user": "While we review this, you can take action against %s" + "dont_want_to_see_this": "Не хочете бачити це?", + "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "Якщо бачите щось, що вам не подобається в Mastodon, то можна вилучити людину зі свого оточення.", + "unfollow": "Відписатися", + "unfollowed": "Відписалися від", + "unfollow_user": "Відписатися від %s", + "mute_user": "Ігнорувати %s", + "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "Ви не побачите їхні дописи чи репости на вашій домашній стрічці. Вони не знатимуть, що ви ігноруєте їх.", + "block_user": "Заблокувати %s", + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "Вони більше не зможуть стежити або бачити Ваші пости, але вони зможуть побачити, що вони були заблоковані.", + "while_we_review_this_you_can_take_action_against_user": "Поки ми переглядаємо це, ви можете вжити заходів проти %s" } }, "preview": { "keyboard": { - "close_preview": "Close Preview", - "show_next": "Show Next", - "show_previous": "Show Previous" + "close_preview": "Закрити перегляд", + "show_next": "Показати наступне", + "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" + "tab_bar_hint": "Поточний профіль: %s. Двічі торкніться, щоб показати перемикач ваших профілів", + "dismiss_account_switcher": "Відхилити зміну поточного облікового запису", + "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" + "new_in_mastodon": "Новий в Mastodon", + "multiple_account_switch_intro_description": "Натисніть для переходу між кількома обліковими записами, тримаючи кнопку профілю.", + "accessibility_hint": "Двічі торкніться, щоб закрити цей майстер" }, "bookmark": { - "title": "Bookmarks" + "title": "Закладки" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/uk.lproj/ios-infoPlist.json b/Localization/StringsConvertor/input/uk.lproj/ios-infoPlist.json index c6db73de0..bc953a077 100644 --- a/Localization/StringsConvertor/input/uk.lproj/ios-infoPlist.json +++ b/Localization/StringsConvertor/input/uk.lproj/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": "Використовується, щоб зробити фотографію для статусу публікації", + "NSPhotoLibraryAddUsageDescription": "Використовується для збереження фото в бібліотеку", + "NewPostShortcutItemTitle": "Новий допис", + "SearchShortcutItemTitle": "Пошук" } diff --git a/Localization/StringsConvertor/input/vi.lproj/app.json b/Localization/StringsConvertor/input/vi.lproj/app.json index 963be39c9..3a3c66a66 100644 --- a/Localization/StringsConvertor/input/vi.lproj/app.json +++ b/Localization/StringsConvertor/input/vi.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Xóa bộ nhớ đệm", "message": "Đã xóa %s bộ nhớ đệm." + }, + "translation_failed": { + "title": "Ghi chú", + "message": "Dịch không thành công. Có thể quản trị viên chưa bật dịch trên máy chủ này hoặc máy chủ này đang chạy phiên bản cũ hơn của Mastodon chưa hỗ trợ dịch.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Tạo tài khoản", "see_more": "Xem thêm", "preview": "Xem trước", + "copy": "Chép", "share": "Chia sẻ", "share_user": "Chia sẻ %s", "share_post": "Chia sẻ tút", @@ -91,12 +97,16 @@ "block_domain": "Chặn %s", "unblock_domain": "Bỏ chặn %s", "settings": "Cài đặt", - "delete": "Xóa" + "delete": "Xóa", + "translate_post": { + "title": "Dịch từ %s", + "unknown_language": "Chưa xác định" + } }, "tabs": { "home": "Bảng tin", - "search": "Tìm kiếm", - "notification": "Thông báo", + "search_and_explore": "Tìm và Khám Phá", + "notifications": "Thông báo", "profile": "Trang hồ sơ" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "Nội dung nhạy cảm", "media_content_warning": "Nhấn để hiển thị", "tap_to_reveal": "Nhấn để xem", + "load_embed": "Nạp mã nhúng", + "link_via_user": "%s bởi %s", "poll": { "vote": "Bình chọn", "closed": "Kết thúc" @@ -153,6 +165,7 @@ "show_image": "Hiển thị hình ảnh", "show_gif": "Hiển thị GIF", "show_video_player": "Hiện trình phát video", + "share_link_in_post": "Chia sẻ liên kết trong Tút", "tap_then_hold_to_show_menu": "Nhấn giữ để hiện menu" }, "tag": { @@ -168,6 +181,12 @@ "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." + }, + "translation": { + "translated_from": "Dịch từ %s bằng %s", + "unknown_language": "Không xác định", + "unknown_provider": "Không biết", + "show_original": "Bản gốc" } }, "friendship": { @@ -381,7 +400,7 @@ }, "content_input_placeholder": "Cho thế giới biết bạn đang nghĩ gì", "compose_action": "Đăng", - "replying_to_user": "trả lời %s", + "replying_to_user": "%s viết tiếp", "attachment": { "photo": "ảnh", "video": "video", @@ -444,11 +463,15 @@ "follows_you": "Đang theo dõi bạn" }, "dashboard": { - "posts": "tút", - "following": "theo dõi", - "followers": "người theo dõi" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Đã tham gia", "add_row": "Thêm hàng", "placeholder": { "label": "Nhãn", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "Tút đã lưu" + }, + "followed_tags": { + "title": "Hashtag Theo Dõi", + "header": { + "posts": "tút", + "participants": "người thảo luận", + "posts_today": "tút hôm nay" + }, + "actions": { + "follow": "Theo dõi", + "unfollow": "Ngưng theo dõi" + } } } } diff --git a/Localization/StringsConvertor/input/zh-Hans.lproj/app.json b/Localization/StringsConvertor/input/zh-Hans.lproj/app.json index c503c5186..efe5c422e 100644 --- a/Localization/StringsConvertor/input/zh-Hans.lproj/app.json +++ b/Localization/StringsConvertor/input/zh-Hans.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "清除缓存", "message": "成功清除 %s 缓存。" + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "创建账户", "see_more": "查看更多", "preview": "预览", + "copy": "Copy", "share": "分享", "share_user": "分享 %s", "share_post": "分享帖子", @@ -91,12 +97,16 @@ "block_domain": "屏蔽 %s", "unblock_domain": "解除屏蔽 %s", "settings": "设置", - "delete": "删除" + "delete": "删除", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "主页", - "search": "搜索", - "notification": "通知", + "search_and_explore": "Search and Explore", + "notifications": "通知", "profile": "个人资料" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "敏感内容", "media_content_warning": "点击任意位置显示", "tap_to_reveal": "点击以显示", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "投票", "closed": "已关闭" @@ -153,6 +165,7 @@ "show_image": "显示图片", "show_gif": "显示 GIF", "show_video_player": "显示视频播放器", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "长按以显示菜单" }, "tag": { @@ -168,6 +181,12 @@ "private": "只有作者的关注者才能看到此帖子。", "private_from_me": "只有我的关注者才能看到此帖子。", "direct": "只有提到的用户才能看到此帖子。" + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "关注了你" }, "dashboard": { - "posts": "帖子", - "following": "正在关注", - "followers": "关注者" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "添加", "placeholder": { "label": "标签", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "书签" + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Localization/StringsConvertor/input/zh-Hant.lproj/app.json b/Localization/StringsConvertor/input/zh-Hant.lproj/app.json index e2dfaad64..711084407 100644 --- a/Localization/StringsConvertor/input/zh-Hant.lproj/app.json +++ b/Localization/StringsConvertor/input/zh-Hant.lproj/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "清除快取", "message": "成功清除 %s 快取。" + }, + "translation_failed": { + "title": "備註", + "message": "翻譯失敗。也許管理員未於此伺服器啟用翻譯功能,或此伺服器為未支援翻譯功能之舊版本 Mastodon。", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "新增帳號", "see_more": "檢視更多", "preview": "預覽", + "copy": "複製", "share": "分享", "share_user": "分享 %s", "share_post": "分享嘟文", @@ -91,12 +97,16 @@ "block_domain": "封鎖 %s", "unblock_domain": "解除封鎖 %s", "settings": "設定", - "delete": "刪除" + "delete": "刪除", + "translate_post": { + "title": "翻譯自 %s", + "unknown_language": "未知" + } }, "tabs": { "home": "首頁", - "search": "搜尋", - "notification": "通知", + "search_and_explore": "搜尋與探索", + "notifications": "通知", "profile": "個人檔案" }, "keyboard": { @@ -132,6 +142,8 @@ "sensitive_content": "敏感內容", "media_content_warning": "輕觸任何地方以顯示", "tap_to_reveal": "輕觸以顯示", + "load_embed": "讀取嵌入內容", + "link_via_user": "%s 透過 %s", "poll": { "vote": "投票", "closed": "已關閉" @@ -153,6 +165,7 @@ "show_image": "顯示圖片", "show_gif": "顯示 GIF", "show_video_player": "顯示影片播放器", + "share_link_in_post": "於嘟文中分享鏈結", "tap_then_hold_to_show_menu": "輕觸然後按住以顯示選單" }, "tag": { @@ -168,6 +181,12 @@ "private": "只有他們的跟隨者能看到此嘟文。", "private_from_me": "只有我的跟隨者能看到此嘟文。", "direct": "只有被提及的使用者能看到此嘟文。" + }, + "translation": { + "translated_from": "透過 %s 翻譯 %s", + "unknown_language": "未知", + "unknown_provider": "未知", + "show_original": "顯示原文" } }, "friendship": { @@ -444,11 +463,15 @@ "follows_you": "跟隨了您" }, "dashboard": { - "posts": "嘟文", - "following": "跟隨中", - "followers": "跟隨者" + "my_posts": "嘟文", + "my_following": "正在跟隨", + "my_followers": "跟隨者", + "other_posts": "嘟文", + "other_following": "正在跟隨", + "other_followers": "跟隨者" }, "fields": { + "joined": "加入時間", "add_row": "新增列", "placeholder": { "label": "標籤", @@ -722,6 +745,18 @@ }, "bookmark": { "title": "書籤" + }, + "followed_tags": { + "title": "已跟隨主題標籤", + "header": { + "posts": "嘟文", + "participants": "參與者", + "posts_today": "本日嘟文" + }, + "actions": { + "follow": "跟隨", + "unfollow": "取消跟隨" + } } } } diff --git a/Localization/app.json b/Localization/app.json index ea046bfbc..963b4aed1 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -51,6 +51,11 @@ "clean_cache": { "title": "Clean Cache", "message": "Successfully cleaned %s cache." + }, + "translation_failed": { + "title": "Note", + "message": "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.", + "button": "OK" } }, "controls": { @@ -78,6 +83,7 @@ "sign_up": "Create account", "see_more": "See More", "preview": "Preview", + "copy": "Copy", "share": "Share", "share_user": "Share %s", "share_post": "Share Post", @@ -91,11 +97,15 @@ "block_domain": "Block %s", "unblock_domain": "Unblock %s", "settings": "Settings", - "delete": "Delete" + "delete": "Delete", + "translate_post": { + "title": "Translate from %s", + "unknown_language": "Unknown" + } }, "tabs": { "home": "Home", - "search": "Search", + "search_and_explore": "Search and Explore", "notifications": "Notifications", "profile": "Profile" }, @@ -132,6 +142,8 @@ "sensitive_content": "Sensitive Content", "media_content_warning": "Tap anywhere to reveal", "tap_to_reveal": "Tap to reveal", + "load_embed": "Load Embed", + "link_via_user": "%s via %s", "poll": { "vote": "Vote", "closed": "Closed" @@ -153,6 +165,7 @@ "show_image": "Show image", "show_gif": "Show GIF", "show_video_player": "Show video player", + "share_link_in_post": "Share Link in Post", "tap_then_hold_to_show_menu": "Tap then hold to show menu" }, "tag": { @@ -168,6 +181,18 @@ "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." + }, + "translation": { + "translated_from": "Translated from %s using %s", + "unknown_language": "Unknown", + "unknown_provider": "Unknown", + "show_original": "Shown Original" + }, + "media": { + "accessibility_label": "%s, attachment %d of %d", + "expand_image_hint": "Expands the image. Double-tap and hold to show actions", + "expand_gif_hint": "Expands the GIF. Double-tap and hold to show actions", + "expand_video_hint": "Shows the video player. Double-tap and hold to show actions" } }, "friendship": { @@ -360,7 +385,7 @@ "published": "Published!", "Publishing": "Publishing post...", "accessibility": { - "logo_label": "Logo Button", + "logo_label": "Mastodon", "logo_hint": "Tap to scroll to top and tap again to previous location" } } @@ -444,11 +469,15 @@ "follows_you": "Follows You" }, "dashboard": { - "posts": "posts", - "following": "following", - "followers": "followers" + "my_posts": "posts", + "my_following": "following", + "my_followers": "followers", + "other_posts": "posts", + "other_following": "following", + "other_followers": "followers" }, "fields": { + "joined": "Joined", "add_row": "Add Row", "placeholder": { "label": "Label", @@ -722,6 +751,19 @@ }, "bookmark": { "title": "Bookmarks" + + }, + "followed_tags": { + "title": "Followed Tags", + "header": { + "posts": "posts", + "participants": "participants", + "posts_today": "posts today" + }, + "actions": { + "follow": "Follow", + "unfollow": "Unfollow" + } } } } diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 0c43b71df..3f70434b6 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -23,7 +23,16 @@ 0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D33725E6401400AAD544 /* PickServerCell.swift */; }; 164F0EBC267D4FE400249499 /* BoopSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 164F0EBB267D4FE400249499 /* BoopSound.caf */; }; 18BC7629F65E6DB12CB8416D /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */; }; + 27D701F5292FC2D60031BCBB /* DataSourceFacade+URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27D701F4292FC2D60031BCBB /* DataSourceFacade+URL.swift */; }; + 2A1FE47C2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1FE47B2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift */; }; + 2A1FE47E2938C11200784BF1 /* Collection+IsNotEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1FE47D2938C11200784BF1 /* Collection+IsNotEmpty.swift */; }; + 2A3F6FE3292ECB5E002E6DA7 /* FollowedTagsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A3F6FE2292ECB5E002E6DA7 /* FollowedTagsViewModel.swift */; }; + 2A3F6FE5292F6E44002E6DA7 /* FollowedTagsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A3F6FE4292F6E44002E6DA7 /* FollowedTagsTableViewCell.swift */; }; + 2A506CF4292CD85800059C37 /* FollowedTagsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A506CF3292CD85800059C37 /* FollowedTagsViewController.swift */; }; + 2A506CF6292D040100059C37 /* HashtagTimelineHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A506CF5292D040100059C37 /* HashtagTimelineHeaderView.swift */; }; + 2A76F75C2930D94700B3388D /* HashtagTimelineHeaderViewActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A76F75B2930D94700B3388D /* HashtagTimelineHeaderViewActionButton.swift */; }; 2A82294F29262EE000D2A1F7 /* AppContext+NextAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A82294E29262EE000D2A1F7 /* AppContext+NextAccount.swift */; }; + 2AB12E4629362F27006BC925 /* DataSourceFacade+Translate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AB12E4529362F27006BC925 /* DataSourceFacade+Translate.swift */; }; 2AE244482927831100BDBF7C /* UIImage+SFSymbols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AE244472927831100BDBF7C /* UIImage+SFSymbols.swift */; }; 2D198643261BF09500F0B013 /* SearchResultItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198642261BF09500F0B013 /* SearchResultItem.swift */; }; 2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D198648261C0B8500F0B013 /* SearchResultSection.swift */; }; @@ -66,7 +75,11 @@ 2DAC9E46262FC9FD0062E1A6 /* SuggestionAccountTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DAC9E45262FC9FD0062E1A6 /* SuggestionAccountTableViewCell.swift */; }; 2DCB73FD2615C13900EC03D4 /* SearchRecommendCollectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DCB73FC2615C13900EC03D4 /* SearchRecommendCollectionHeader.swift */; }; 2DE0FACE2615F7AD00CDF649 /* RecommendAccountSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DE0FACD2615F7AD00CDF649 /* RecommendAccountSection.swift */; }; - 2DF123A725C3B0210020F248 /* ActiveLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF123A625C3B0210020F248 /* ActiveLabel.swift */; }; + 357FEEAF29523D470021C9DC /* MastodonSDKDynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 357FEEAE29523D470021C9DC /* MastodonSDKDynamic */; }; + 357FEEB029523D470021C9DC /* MastodonSDKDynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 357FEEAE29523D470021C9DC /* MastodonSDKDynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 357FEEB229523D510021C9DC /* MastodonSDKDynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 357FEEB129523D510021C9DC /* MastodonSDKDynamic */; }; + 357FEEB629523D5C0021C9DC /* MastodonSDKDynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 357FEEB529523D5C0021C9DC /* MastodonSDKDynamic */; }; + 357FEEBA29523D660021C9DC /* MastodonSDKDynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 357FEEB929523D660021C9DC /* MastodonSDKDynamic */; }; 5B24BBDA262DB14800A9381B /* ReportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B24BBD7262DB14800A9381B /* ReportViewModel.swift */; }; 5B24BBDB262DB14800A9381B /* ReportStatusViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B24BBD8262DB14800A9381B /* ReportStatusViewModel+Diffable.swift */; }; 5B90C45E262599800002E742 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B90C456262599800002E742 /* SettingsViewModel.swift */; }; @@ -88,6 +101,9 @@ 62FD27D12893707600B205C5 /* BookmarkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FD27D02893707600B205C5 /* BookmarkViewController.swift */; }; 62FD27D32893707B00B205C5 /* BookmarkViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FD27D22893707B00B205C5 /* BookmarkViewController+DataSourceProvider.swift */; }; 62FD27D52893708A00B205C5 /* BookmarkViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FD27D42893708A00B205C5 /* BookmarkViewModel+Diffable.swift */; }; + 85904C02293BC0EB0011C817 /* ImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85904C01293BC0EB0011C817 /* ImageProvider.swift */; }; + 85904C04293BC1940011C817 /* URLActivityItemWithMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85904C03293BC1940011C817 /* URLActivityItemWithMetadata.swift */; }; + 85BC11B32932414900E191CD /* AltViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85BC11B22932414900E191CD /* AltViewController.swift */; }; 87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A4ABE34829701A4496C5BB64 /* Pods_Mastodon.framework */; }; C24C97032922F30500BAE8CB /* RefreshControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24C97022922F30500BAE8CB /* RefreshControl.swift */; }; D87BFC8B291D5C6B00FEE264 /* MastodonLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */; }; @@ -119,7 +135,6 @@ DB0618032785A7100030EE79 /* RegisterSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618022785A7100030EE79 /* RegisterSection.swift */; }; DB0618052785A73D0030EE79 /* RegisterItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618042785A73D0030EE79 /* RegisterItem.swift */; }; DB0A322E280EE9FD001729D2 /* DiscoveryIntroBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */; }; - DB0C947726A7FE840088FB11 /* NotificationAvatarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */; }; DB0EF72B26FDB1D200347686 /* SidebarListCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0EF72A26FDB1D200347686 /* SidebarListCollectionViewCell.swift */; }; DB0EF72E26FDB24F00347686 /* SidebarListContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0EF72D26FDB24F00347686 /* SidebarListContentView.swift */; }; DB0F8150264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0F814F264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift */; }; @@ -159,10 +174,6 @@ DB1FD44425F26CCC004CFCFC /* PickServerSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1FD44325F26CCC004CFCFC /* PickServerSection.swift */; }; DB1FD45025F26FA1004CFCFC /* MastodonPickServerViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1FD44F25F26FA1004CFCFC /* MastodonPickServerViewModel+Diffable.swift */; }; DB1FD45A25F27898004CFCFC /* CategoryPickerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1FD45925F27898004CFCFC /* CategoryPickerItem.swift */; }; - DB22C92228E700A10082A9E9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DB22C92128E700A10082A9E9 /* MastodonSDK */; }; - DB22C92428E700A80082A9E9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DB22C92328E700A80082A9E9 /* MastodonSDK */; }; - DB22C92628E700AF0082A9E9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DB22C92528E700AF0082A9E9 /* MastodonSDK */; }; - DB22C92828E700B70082A9E9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DB22C92728E700B70082A9E9 /* MastodonSDK */; }; DB2B3ABC25E37E15007045F9 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DB2B3ABE25E37E15007045F9 /* InfoPlist.strings */; }; DB2F073525E8ECF000957B2D /* AuthenticationViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB2F073325E8ECF000957B2D /* AuthenticationViewModel.swift */; }; DB2FF510260B113300ADA9FE /* ComposeStatusPollExpiresOptionCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB2FF50F260B113300ADA9FE /* ComposeStatusPollExpiresOptionCollectionViewCell.swift */; }; @@ -296,8 +307,6 @@ DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */; }; DB7274F4273BB9B200577D95 /* ListBatchFetchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7274F3273BB9B200577D95 /* ListBatchFetchViewModel.swift */; }; DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73B48F261F030A002E9E9F /* SafariActivity.swift */; }; - DB73BF4927140BA300781945 /* UICollectionViewDiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF4827140BA300781945 /* UICollectionViewDiffableDataSource.swift */; }; - DB73BF4B27140C0800781945 /* UITableViewDiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73BF4A27140C0800781945 /* UITableViewDiffableDataSource.swift */; }; DB75BF1E263C1C1B00EDBF1F /* CustomScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB75BF1D263C1C1B00EDBF1F /* CustomScheduler.swift */; }; DB789A0B25F9F2950071ACA0 /* ComposeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */; }; DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */; }; @@ -482,6 +491,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 357FEEB029523D470021C9DC /* MastodonSDKDynamic in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -520,7 +530,16 @@ 0FB3D33725E6401400AAD544 /* PickServerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCell.swift; sourceTree = ""; }; 164F0EBB267D4FE400249499 /* BoopSound.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = BoopSound.caf; sourceTree = ""; }; 1D6D967E77A5357E2C6110D9 /* Pods-Mastodon.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk - debug.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk - debug.xcconfig"; sourceTree = ""; }; + 27D701F4292FC2D60031BCBB /* DataSourceFacade+URL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceFacade+URL.swift"; sourceTree = ""; }; + 2A1FE47B2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FollowedTagsViewModel+DiffableDataSource.swift"; sourceTree = ""; }; + 2A1FE47D2938C11200784BF1 /* Collection+IsNotEmpty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+IsNotEmpty.swift"; sourceTree = ""; }; + 2A3F6FE2292ECB5E002E6DA7 /* FollowedTagsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowedTagsViewModel.swift; sourceTree = ""; }; + 2A3F6FE4292F6E44002E6DA7 /* FollowedTagsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowedTagsTableViewCell.swift; sourceTree = ""; }; + 2A506CF3292CD85800059C37 /* FollowedTagsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowedTagsViewController.swift; sourceTree = ""; }; + 2A506CF5292D040100059C37 /* HashtagTimelineHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagTimelineHeaderView.swift; sourceTree = ""; }; + 2A76F75B2930D94700B3388D /* HashtagTimelineHeaderViewActionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagTimelineHeaderViewActionButton.swift; sourceTree = ""; }; 2A82294E29262EE000D2A1F7 /* AppContext+NextAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppContext+NextAccount.swift"; sourceTree = ""; }; + 2AB12E4529362F27006BC925 /* DataSourceFacade+Translate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceFacade+Translate.swift"; sourceTree = ""; }; 2AE244472927831100BDBF7C /* UIImage+SFSymbols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+SFSymbols.swift"; sourceTree = ""; }; 2D198642261BF09500F0B013 /* SearchResultItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultItem.swift; sourceTree = ""; }; 2D198648261C0B8500F0B013 /* SearchResultSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultSection.swift; sourceTree = ""; }; @@ -564,7 +583,6 @@ 2DAC9E45262FC9FD0062E1A6 /* SuggestionAccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionAccountTableViewCell.swift; sourceTree = ""; }; 2DCB73FC2615C13900EC03D4 /* SearchRecommendCollectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchRecommendCollectionHeader.swift; sourceTree = ""; }; 2DE0FACD2615F7AD00CDF649 /* RecommendAccountSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendAccountSection.swift; sourceTree = ""; }; - 2DF123A625C3B0210020F248 /* ActiveLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveLabel.swift; sourceTree = ""; }; 2E1F6A67FDF9771D3E064FDC /* Pods-Mastodon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.debug.xcconfig"; sourceTree = ""; }; 3B7FD8F28DDA8FBCE5562B78 /* Pods-NotificationService.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk - debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk - debug.xcconfig"; sourceTree = ""; }; 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon_MastodonUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -600,6 +618,9 @@ 7CB58D292DA7ACEF179A9050 /* Pods-Mastodon.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.profile.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.profile.xcconfig"; sourceTree = ""; }; 7CEFFAE9AF9284B13C0A758D /* Pods-MastodonTests.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.asdk - debug.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.asdk - debug.xcconfig"; sourceTree = ""; }; 819CEC9DCAD8E8E7BD85A7BB /* Pods-Mastodon.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk.xcconfig"; sourceTree = ""; }; + 85904C01293BC0EB0011C817 /* ImageProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageProvider.swift; sourceTree = ""; }; + 85904C03293BC1940011C817 /* URLActivityItemWithMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLActivityItemWithMetadata.swift; sourceTree = ""; }; + 85BC11B22932414900E191CD /* AltViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AltViewController.swift; sourceTree = ""; }; 8850E70A1D5FF51432E43653 /* Pods-Mastodon-MastodonUITests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; sourceTree = ""; }; 8E79CCBE51FBC3F7FE8CF49F /* Pods-MastodonTests.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.release snapshot.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.release snapshot.xcconfig"; sourceTree = ""; }; 8ED8C4B1F1BA2DCFF2926BB1 /* Pods-Mastodon-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-NotificationService/Pods-Mastodon-NotificationService.debug.xcconfig"; sourceTree = ""; }; @@ -647,7 +668,6 @@ DB0618042785A73D0030EE79 /* RegisterItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterItem.swift; sourceTree = ""; }; DB0618062785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonRegisterViewModel+Diffable.swift"; sourceTree = ""; }; DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryIntroBannerView.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 = ""; }; DB0EF72D26FDB24F00347686 /* SidebarListContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarListContentView.swift; sourceTree = ""; }; DB0F814E264CFFD300F2A12B /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -859,8 +879,6 @@ DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewModel.swift; sourceTree = ""; }; DB7274F3273BB9B200577D95 /* ListBatchFetchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListBatchFetchViewModel.swift; sourceTree = ""; }; DB73B48F261F030A002E9E9F /* SafariActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariActivity.swift; sourceTree = ""; }; - DB73BF4827140BA300781945 /* UICollectionViewDiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UICollectionViewDiffableDataSource.swift; sourceTree = ""; }; - DB73BF4A27140C0800781945 /* UITableViewDiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITableViewDiffableDataSource.swift; sourceTree = ""; }; DB75BF1D263C1C1B00EDBF1F /* CustomScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomScheduler.swift; sourceTree = ""; }; DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewController.swift; sourceTree = ""; }; DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewModel.swift; sourceTree = ""; }; @@ -1065,7 +1083,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DB22C92428E700A80082A9E9 /* MastodonSDK in Frameworks */, + 357FEEAF29523D470021C9DC /* MastodonSDKDynamic in Frameworks */, DBF96326262EC0A6001D8D25 /* AuthenticationServices.framework in Frameworks */, 87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */, ); @@ -1092,7 +1110,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DB22C92828E700B70082A9E9 /* MastodonSDK in Frameworks */, + 357FEEBA29523D660021C9DC /* MastodonSDKDynamic in Frameworks */, DB8FABC726AEC7B2008E5AF4 /* Intents.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1101,7 +1119,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DB22C92628E700AF0082A9E9 /* MastodonSDK in Frameworks */, + 357FEEB629523D5C0021C9DC /* MastodonSDKDynamic in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1109,7 +1127,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DB22C92228E700A10082A9E9 /* MastodonSDK in Frameworks */, + 357FEEB229523D510021C9DC /* MastodonSDKDynamic in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1124,6 +1142,8 @@ 0F202200261326E6000C64BF /* HashtagTimelineViewModel.swift */, 0F20220626134DA4000C64BF /* HashtagTimelineViewModel+Diffable.swift */, 0F20222C261457EE000C64BF /* HashtagTimelineViewModel+State.swift */, + 2A506CF5292D040100059C37 /* HashtagTimelineHeaderView.swift */, + 2A76F75B2930D94700B3388D /* HashtagTimelineHeaderViewActionButton.swift */, ); path = HashtagTimeline; sourceTree = ""; @@ -1226,6 +1246,17 @@ path = Pods; sourceTree = ""; }; + 2A506CF2292CD83B00059C37 /* FollowedTags */ = { + isa = PBXGroup; + children = ( + 2A506CF3292CD85800059C37 /* FollowedTagsViewController.swift */, + 2A3F6FE2292ECB5E002E6DA7 /* FollowedTagsViewModel.swift */, + 2A1FE47B2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift */, + 2A3F6FE4292F6E44002E6DA7 /* FollowedTagsTableViewCell.swift */, + ); + path = FollowedTags; + sourceTree = ""; + }; 2D152A8A25C295B8009AA50C /* Content */ = { isa = PBXGroup; children = ( @@ -1602,14 +1633,6 @@ path = View; sourceTree = ""; }; - DB0C947826A7FE950088FB11 /* Button */ = { - isa = PBXGroup; - children = ( - DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */, - ); - path = Button; - sourceTree = ""; - }; DB0EF72C26FDB1D600347686 /* View */ = { isa = PBXGroup; children = ( @@ -1942,6 +1965,7 @@ DB6180F026391CAB0018D199 /* Image */, DB6180E1263919780018D199 /* Paging */, DB6180DC263918E30018D199 /* MediaPreviewViewController.swift */, + 85BC11B22932414900E191CD /* AltViewController.swift */, DB6180F926391F2E0018D199 /* MediaPreviewViewModel.swift */, ); path = MediaPreview; @@ -2089,10 +2113,12 @@ DB63F778279ABF9C00455B82 /* DataSourceFacade+Reblog.swift */, DB63F77A279ACAE500455B82 /* DataSourceFacade+Favorite.swift */, DB0FCB67279507EF006C02E2 /* DataSourceFacade+Meta.swift */, + 27D701F4292FC2D60031BCBB /* DataSourceFacade+URL.swift */, DB0FCB79279576A2006C02E2 /* DataSourceFacade+Thread.swift */, DB63F74627990B0600455B82 /* DataSourceFacade+Hashtag.swift */, DB63F7532799491600455B82 /* DataSourceFacade+SearchHistory.swift */, DB159C2A27A17BAC0068DC77 /* DataSourceFacade+Media.swift */, + 2AB12E4529362F27006BC925 /* DataSourceFacade+Translate.swift */, DB697DD5278F4C29004EF2F7 /* DataSourceProvider.swift */, DB697DDA278F4DE3004EF2F7 /* DataSourceProvider+StatusTableViewCellDelegate.swift */, DB023D2927A0FE5C005AC798 /* DataSourceProvider+NotificationTableViewCellDelegate.swift */, @@ -2225,7 +2251,6 @@ DB8AF56225C138BC002E6C99 /* Extension */ = { isa = PBXGroup; children = ( - 2DF123A625C3B0210020F248 /* ActiveLabel.swift */, 2A82294E29262EE000D2A1F7 /* AppContext+NextAccount.swift */, 5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */, 2D206B8525F5FB0900143C56 /* Double.swift */, @@ -2248,8 +2273,7 @@ DB9E0D6E25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift */, 2AE244472927831100BDBF7C /* UIImage+SFSymbols.swift */, DBCC3B2F261440A50045B23D /* UITabBarController.swift */, - DB73BF4827140BA300781945 /* UICollectionViewDiffableDataSource.swift */, - DB73BF4A27140C0800781945 /* UITableViewDiffableDataSource.swift */, + 2A1FE47D2938C11200784BF1 /* Collection+IsNotEmpty.swift */, ); path = Extension; sourceTree = ""; @@ -2358,7 +2382,6 @@ isa = PBXGroup; children = ( DB63F765279A5E5600455B82 /* NotificationTimeline */, - DB0C947826A7FE950088FB11 /* Button */, 2D35237F26256F470031AF25 /* Cell */, DB9D6BF725E4F5690051B173 /* NotificationViewController.swift */, 2D607AD726242FC500B70763 /* NotificationViewModel.swift */, @@ -2369,6 +2392,7 @@ DB9D6C0825E4F5A60051B173 /* Profile */ = { isa = PBXGroup; children = ( + 2A506CF2292CD83B00059C37 /* FollowedTags */, 62047EBE28874C8F00A3BA5D /* Bookmark */, DBB525462611ED57002F1F29 /* Header */, DBB525262611EBDA002F1F29 /* Paging */, @@ -2517,6 +2541,8 @@ isa = PBXGroup; children = ( DBF3B7402733EB9400E21627 /* MastodonLocalCode.swift */, + 85904C01293BC0EB0011C817 /* ImageProvider.swift */, + 85904C03293BC1940011C817 /* URLActivityItemWithMetadata.swift */, ); path = Helper; sourceTree = ""; @@ -2717,7 +2743,7 @@ ); name = Mastodon; packageProductDependencies = ( - DB22C92328E700A80082A9E9 /* MastodonSDK */, + 357FEEAE29523D470021C9DC /* MastodonSDKDynamic */, ); productName = Mastodon; productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */; @@ -2776,7 +2802,7 @@ ); name = MastodonIntent; packageProductDependencies = ( - DB22C92728E700B70082A9E9 /* MastodonSDK */, + 357FEEB929523D660021C9DC /* MastodonSDKDynamic */, ); productName = MastodonIntent; productReference = DB8FABC626AEC7B2008E5AF4 /* MastodonIntent.appex */; @@ -2796,7 +2822,7 @@ ); name = ShareActionExtension; packageProductDependencies = ( - DB22C92528E700AF0082A9E9 /* MastodonSDK */, + 357FEEB529523D5C0021C9DC /* MastodonSDKDynamic */, ); productName = ShareActionExtension; productReference = DBC6461226A170AB00B0E31B /* ShareActionExtension.appex */; @@ -2816,7 +2842,7 @@ ); name = NotificationService; packageProductDependencies = ( - DB22C92128E700A10082A9E9 /* MastodonSDK */, + 357FEEB129523D510021C9DC /* MastodonSDKDynamic */, ); productName = NotificationService; productReference = DBF8AE13263293E400C9C23C /* NotificationService.appex */; @@ -3142,6 +3168,7 @@ DB03A793272A7E5700EE37C5 /* SidebarListHeaderView.swift in Sources */, DB4FFC2B269EC39600D62E92 /* SearchToSearchDetailViewControllerAnimatedTransitioning.swift in Sources */, DB5B7298273112C800081888 /* FollowingListViewModel.swift in Sources */, + 27D701F5292FC2D60031BCBB /* DataSourceFacade+URL.swift in Sources */, 0FB3D2F725E4C24D00AAD544 /* MastodonPickServerViewModel.swift in Sources */, DB5B54AE2833C15F00DEF8B2 /* UserListViewModel+Diffable.swift in Sources */, DB482A3F261331E8008AE74C /* UserTimelineViewModel+State.swift in Sources */, @@ -3168,6 +3195,7 @@ 62FD27D52893708A00B205C5 /* BookmarkViewModel+Diffable.swift in Sources */, DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */, 2D364F7225E66D7500204FDC /* MastodonResendEmailViewController.swift in Sources */, + 85904C04293BC1940011C817 /* URLActivityItemWithMetadata.swift in Sources */, DB68A06325E905E000CFDF14 /* UIApplication.swift in Sources */, DB02CDAB26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift in Sources */, DBEFCD80282A2AA900C0ABEA /* ReportServerRulesViewModel.swift in Sources */, @@ -3234,7 +3262,6 @@ DB603113279EBEBA00A935FE /* DataSourceFacade+Block.swift in Sources */, DB63F777279A9A2A00455B82 /* NotificationView+Configuration.swift in Sources */, DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */, - DB0C947726A7FE840088FB11 /* NotificationAvatarButton.swift in Sources */, 5B90C461262599800002E742 /* SettingsLinkTableViewCell.swift in Sources */, DB6180DD263918E30018D199 /* MediaPreviewViewController.swift in Sources */, DBE3CDEC261C6B2900430CC6 /* FavoriteViewController.swift in Sources */, @@ -3257,6 +3284,7 @@ DBF1572F27046F1A00EC00B7 /* SecondaryPlaceholderViewController.swift in Sources */, 2D4AD8A826316D3500613EFC /* SelectedAccountItem.swift in Sources */, DBE3CDFB261C6CA500430CC6 /* FavoriteViewModel.swift in Sources */, + 2AB12E4629362F27006BC925 /* DataSourceFacade+Translate.swift in Sources */, DBE3CE01261D623D00430CC6 /* FavoriteViewModel+State.swift in Sources */, 2D82BA0525E7897700E36F0F /* MastodonResendEmailViewModelNavigationDelegateShim.swift in Sources */, 2D38F1EB25CD477000561493 /* HomeTimelineViewModel+LoadLatestState.swift in Sources */, @@ -3273,10 +3301,8 @@ DB5B549D2833A67400DEF8B2 /* FamiliarFollowersViewModel.swift in Sources */, DBB9759C262462E1004620BD /* ThreadMetaView.swift in Sources */, DB5B729E273113F300081888 /* FollowingListViewModel+State.swift in Sources */, - 2DF123A725C3B0210020F248 /* ActiveLabel.swift in Sources */, DBF9814C265E339500E4BA07 /* ProfileFieldAddEntryCollectionViewCell.swift in Sources */, DB63F76227996B6600455B82 /* SearchHistoryViewController+DataSourceProvider.swift in Sources */, - DB73BF4927140BA300781945 /* UICollectionViewDiffableDataSource.swift in Sources */, DBA5E7AB263BD3F5004598BB /* TimelineTableViewCellContextMenuConfiguration.swift in Sources */, DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */, 2AE244482927831100BDBF7C /* UIImage+SFSymbols.swift in Sources */, @@ -3290,20 +3316,24 @@ 2D82B9FF25E7863200E36F0F /* OnboardingViewControllerAppearance.swift in Sources */, DB025B78278D606A002F581E /* StatusItem.swift in Sources */, DB697DD4278F4927004EF2F7 /* StatusTableViewCellDelegate.swift in Sources */, + 2A506CF6292D040100059C37 /* HashtagTimelineHeaderView.swift in Sources */, DBA5E7A5263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift in Sources */, DB3E6FF52807C40300B035AE /* DiscoveryForYouViewController.swift in Sources */, 2D38F1E525CD46C100561493 /* HomeTimelineViewModel.swift in Sources */, DB0FCB842796B2A2006C02E2 /* FavoriteViewController+DataSourceProvider.swift in Sources */, DB0FCB68279507EF006C02E2 /* DataSourceFacade+Meta.swift in Sources */, + 2A1FE47E2938C11200784BF1 /* Collection+IsNotEmpty.swift in Sources */, 2D84350525FF858100EECE90 /* UIScrollView.swift in Sources */, 6213AF5A28939C8400BCADB6 /* BookmarkViewModel.swift in Sources */, 5B24BBDB262DB14800A9381B /* ReportStatusViewModel+Diffable.swift in Sources */, DB4F0968269ED8AD00D62E92 /* SearchHistoryTableHeaderView.swift in Sources */, 0FB3D2FE25E4CB6400AAD544 /* OnboardingHeadlineTableViewCell.swift in Sources */, 5DA732CC2629CEF500A92342 /* UIView+Remove.swift in Sources */, + 2A506CF4292CD85800059C37 /* FollowedTagsViewController.swift in Sources */, DB1D843026566512000346B3 /* KeyboardPreference.swift in Sources */, DB852D1926FAEB6B00FC9D81 /* SidebarViewController.swift in Sources */, 2D206B9225F60EA700143C56 /* UIControl.swift in Sources */, + 85904C02293BC0EB0011C817 /* ImageProvider.swift in Sources */, DBDFF1932805554900557A48 /* DiscoveryPostsViewModel.swift in Sources */, DB3E6FE72806A7A200B035AE /* DiscoveryItem.swift in Sources */, DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */, @@ -3362,7 +3392,6 @@ DB1E346825F518E20079D7DF /* CategoryPickerSection.swift in Sources */, DB7274F4273BB9B200577D95 /* ListBatchFetchViewModel.swift in Sources */, DB0618052785A73D0030EE79 /* RegisterItem.swift in Sources */, - DB73BF4B27140C0800781945 /* UITableViewDiffableDataSource.swift in Sources */, DBB525642612C988002F1F29 /* MeProfileViewModel.swift in Sources */, DB3EA8EF281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift in Sources */, DB6B74EF272FB55000C70B6E /* FollowerListViewController.swift in Sources */, @@ -3373,6 +3402,7 @@ DB938EED2623F79B00E5B6C1 /* ThreadViewModel.swift in Sources */, DB6988DE2848D11C002398EF /* PagerTabStripNavigateable.swift in Sources */, 2DCB73FD2615C13900EC03D4 /* SearchRecommendCollectionHeader.swift in Sources */, + 2A1FE47C2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift in Sources */, DB852D1C26FB021500FC9D81 /* RootSplitViewController.swift in Sources */, DB697DD1278F4871004EF2F7 /* AutoGenerateTableViewDelegate.swift in Sources */, DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */, @@ -3464,6 +3494,7 @@ DBCC3B30261440A50045B23D /* UITabBarController.swift in Sources */, DB3E6FE42806A5B800B035AE /* DiscoverySection.swift in Sources */, DB8190C62601FF0400020C08 /* AttachmentContainerView.swift in Sources */, + 2A76F75C2930D94700B3388D /* HashtagTimelineHeaderViewActionButton.swift in Sources */, DB697DDB278F4DE3004EF2F7 /* DataSourceProvider+StatusTableViewCellDelegate.swift in Sources */, DB87D4512609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift in Sources */, DBB45B5627B39FC9002DC5A7 /* MediaPreviewVideoViewController.swift in Sources */, @@ -3472,6 +3503,7 @@ DB67D08627312E67006A36CF /* WizardViewController.swift in Sources */, DB6746EB278ED8B0008A6B94 /* PollOptionView+Configuration.swift in Sources */, DB0F9D54283EB3C000379AF8 /* ProfileHeaderView+ViewModel.swift in Sources */, + 2A3F6FE3292ECB5E002E6DA7 /* FollowedTagsViewModel.swift in Sources */, DBFEEC99279BDCDE004F81DD /* ProfileAboutViewModel.swift in Sources */, 2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */, DB4F097B26A039FF00D62E92 /* SearchHistorySection.swift in Sources */, @@ -3488,6 +3520,7 @@ DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */, 2D4AD8A226316CD200613EFC /* SelectedAccountSection.swift in Sources */, DB3EA8F1281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift in Sources */, + 85BC11B32932414900E191CD /* AltViewController.swift in Sources */, DB63F775279A997D00455B82 /* NotificationTableViewCell+ViewModel.swift in Sources */, DB98EB5927B109890082E365 /* ReportSupplementaryViewController.swift in Sources */, DB0617EB277EF3820030EE79 /* GradientBorderView.swift in Sources */, @@ -3502,6 +3535,7 @@ 5BB04FF5262F0E6D0043BFF6 /* ReportSection.swift in Sources */, DBEFCD82282A2AB100C0ABEA /* ReportServerRulesView.swift in Sources */, DBA94436265CBB7400C537E1 /* ProfileFieldItem.swift in Sources */, + 2A3F6FE5292F6E44002E6DA7 /* FollowedTagsTableViewCell.swift in Sources */, C24C97032922F30500BAE8CB /* RefreshControl.swift in Sources */, DB023D2A27A0FE5C005AC798 /* DataSourceProvider+NotificationTableViewCellDelegate.swift in Sources */, DB98EB6027B10E150082E365 /* ReportCommentTableViewCell.swift in Sources */, @@ -3779,7 +3813,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INTENTS_CODEGEN_LANGUAGE = Swift; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -3837,7 +3871,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INTENTS_CODEGEN_LANGUAGE = Swift; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -3864,7 +3898,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.4.8; + MARKETING_VERSION = 1.4.10; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -3888,12 +3922,13 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; + EXCLUDED_SOURCE_FILE_NAMES = "Mastodon/Resources/Preview\\ Assets.xcassets"; INFOPLIST_FILE = Mastodon/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.4.8; + MARKETING_VERSION = 1.4.10; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4039,7 +4074,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INTENTS_CODEGEN_LANGUAGE = Swift; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -4066,7 +4101,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.4.8; + MARKETING_VERSION = 1.4.10; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4321,7 +4356,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INTENTS_CODEGEN_LANGUAGE = Swift; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -4349,7 +4384,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.4.8; + MARKETING_VERSION = 1.4.10; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4594,21 +4629,21 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ - DB22C92128E700A10082A9E9 /* MastodonSDK */ = { + 357FEEAE29523D470021C9DC /* MastodonSDKDynamic */ = { isa = XCSwiftPackageProductDependency; - productName = MastodonSDK; + productName = MastodonSDKDynamic; }; - DB22C92328E700A80082A9E9 /* MastodonSDK */ = { + 357FEEB129523D510021C9DC /* MastodonSDKDynamic */ = { isa = XCSwiftPackageProductDependency; - productName = MastodonSDK; + productName = MastodonSDKDynamic; }; - DB22C92528E700AF0082A9E9 /* MastodonSDK */ = { + 357FEEB529523D5C0021C9DC /* MastodonSDKDynamic */ = { isa = XCSwiftPackageProductDependency; - productName = MastodonSDK; + productName = MastodonSDKDynamic; }; - DB22C92728E700B70082A9E9 /* MastodonSDK */ = { + 357FEEB929523D660021C9DC /* MastodonSDKDynamic */ = { isa = XCSwiftPackageProductDependency; - productName = MastodonSDK; + productName = MastodonSDKDynamic; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index c3019010a..3dc73c020 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -173,6 +173,7 @@ extension SceneCoordinator { case rebloggedBy(viewModel: UserListViewModel) case favoritedBy(viewModel: UserListViewModel) case bookmark(viewModel: BookmarkViewModel) + case followedTags(viewModel: FollowedTagsViewModel) // setting case settings(viewModel: SettingsViewModel) @@ -448,6 +449,10 @@ private extension SceneCoordinator { let _viewController = BookmarkViewController() _viewController.viewModel = viewModel viewController = _viewController + case .followedTags(let viewModel): + let _viewController = FollowedTagsViewController() + _viewController.viewModel = viewModel + viewController = _viewController case .favorite(let viewModel): let _viewController = FavoriteViewController() _viewController.viewModel = viewModel diff --git a/Mastodon/Diffable/Notification/NotificationSection.swift b/Mastodon/Diffable/Notification/NotificationSection.swift index 387affbc7..0271aac20 100644 --- a/Mastodon/Diffable/Notification/NotificationSection.swift +++ b/Mastodon/Diffable/Notification/NotificationSection.swift @@ -76,6 +76,7 @@ extension NotificationSection { viewModel: NotificationTableViewCell.ViewModel, configuration: Configuration ) { + cell.notificationView.viewModel.context = context cell.notificationView.viewModel.authContext = configuration.authContext StatusSection.setupStatusPollDataSource( diff --git a/Mastodon/Diffable/Onboarding/PickServerSection.swift b/Mastodon/Diffable/Onboarding/PickServerSection.swift index ef7ca5972..1af5b23c6 100644 --- a/Mastodon/Diffable/Onboarding/PickServerSection.swift +++ b/Mastodon/Diffable/Onboarding/PickServerSection.swift @@ -77,7 +77,7 @@ extension PickServerSection { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineHeightMultiple = 1.12 let valueAttributedString = NSAttributedString( - string: parseUsersCount(server.totalUsers), + string: server.totalUsers.asAbbreviatedCountString(), attributes: [ .paragraphStyle: paragraphStyle ] @@ -125,17 +125,6 @@ extension PickServerSection { } .store(in: &cell.disposeBag) } - - private static func parseUsersCount(_ usersCount: Int) -> String { - switch usersCount { - case 0..<1000: - return "\(usersCount)" - default: - let usersCountInThousand = Float(usersCount) / 1000.0 - return String(format: "%.1fK", usersCountInThousand) - } - } - } extension PickServerSection { diff --git a/Mastodon/Diffable/Profile/ProfileFieldItem.swift b/Mastodon/Diffable/Profile/ProfileFieldItem.swift index e33a2f883..37d08bc52 100644 --- a/Mastodon/Diffable/Profile/ProfileFieldItem.swift +++ b/Mastodon/Diffable/Profile/ProfileFieldItem.swift @@ -11,10 +11,10 @@ import MastodonSDK import MastodonMeta enum ProfileFieldItem: Hashable { + case createdAt(date: Date) case field(field: FieldValue) case editField(field: FieldValue) case addEntry - case noResult } extension ProfileFieldItem { diff --git a/Mastodon/Diffable/Profile/ProfileFieldSection.swift b/Mastodon/Diffable/Profile/ProfileFieldSection.swift index 6e57e6af9..10946915d 100644 --- a/Mastodon/Diffable/Profile/ProfileFieldSection.swift +++ b/Mastodon/Diffable/Profile/ProfileFieldSection.swift @@ -33,44 +33,60 @@ extension ProfileFieldSection { collectionView.register(ProfileFieldCollectionViewHeaderFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: ProfileFieldCollectionViewHeaderFooterView.footerReuseIdentifer) let fieldCellRegistration = UICollectionView.CellRegistration { cell, indexPath, item in - guard case let .field(field) = item else { return } + let key, value: String + let emojiMeta: MastodonContent.Emojis + let verified: Bool + + switch item { + case .field(field: let field): + key = field.name.value + value = field.value.value + emojiMeta = field.emojiMeta + verified = field.verifiedAt.value != nil + case .createdAt(date: let date): + key = L10n.Scene.Profile.Fields.joined + let formatter = DateFormatter() + formatter.dateStyle = .medium + formatter.timeStyle = .none + value = formatter.string(from: date) + emojiMeta = [:] + verified = false + default: return + } // set key + let keyColor = verified ? Asset.Scene.Profile.About.bioAboutFieldVerifiedText.color : Asset.Colors.Label.secondary.color do { - let mastodonContent = MastodonContent(content: field.name.value, emojis: field.emojiMeta) + let mastodonContent = MastodonContent(content: key, emojis: emojiMeta) let metaContent = try MastodonMetaContent.convert(document: mastodonContent) + cell.keyMetaLabel.textAttributes[.foregroundColor] = keyColor cell.keyMetaLabel.configure(content: metaContent) } catch { - let content = PlaintextMetaContent(string: field.name.value) + let content = PlaintextMetaContent(string: key) +// cell.keyMetaLabel.textAttributes[.foregroundColor] = keyColor cell.keyMetaLabel.configure(content: content) } // set value + let linkColor = verified ? Asset.Scene.Profile.About.bioAboutFieldVerifiedText.color : Asset.Colors.brand.color do { - let mastodonContent = MastodonContent(content: field.value.value, emojis: field.emojiMeta) + let mastodonContent = MastodonContent(content: value, emojis: emojiMeta) let metaContent = try MastodonMetaContent.convert(document: mastodonContent) - cell.valueMetaLabel.linkAttributes[.foregroundColor] = Asset.Colors.brand.color - if field.verifiedAt.value != nil { - cell.valueMetaLabel.linkAttributes[.foregroundColor] = Asset.Scene.Profile.About.bioAboutFieldVerifiedLink.color - } + cell.valueMetaLabel.linkAttributes[.foregroundColor] = linkColor cell.valueMetaLabel.configure(content: metaContent) } catch { - let content = PlaintextMetaContent(string: field.value.value) + let content = PlaintextMetaContent(string: value) + cell.valueMetaLabel.linkAttributes[.foregroundColor] = linkColor cell.valueMetaLabel.configure(content: content) } // set background var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell() - backgroundConfiguration.backgroundColor = UIColor.secondarySystemBackground - if (field.verifiedAt.value != nil) { - backgroundConfiguration.backgroundColor = Asset.Scene.Profile.About.bioAboutFieldVerifiedBackground.color - } + backgroundConfiguration.backgroundColor = verified ? Asset.Scene.Profile.About.bioAboutFieldVerifiedBackground.color : UIColor.secondarySystemBackground cell.backgroundConfiguration = backgroundConfiguration // set checkmark and edit menu label - cell.checkmark.isHidden = true - cell.checkmarkPopoverString = nil - if let verifiedAt = field.verifiedAt.value { + if case .field(let field) = item, let verifiedAt = field.verifiedAt.value { cell.checkmark.isHidden = false let formatter = DateFormatter() formatter.dateStyle = .medium @@ -78,6 +94,9 @@ extension ProfileFieldSection { let dateString = formatter.string(from: verifiedAt) cell.checkmark.accessibilityLabel = L10n.Scene.Profile.Fields.Verified.long(dateString) cell.checkmarkPopoverString = L10n.Scene.Profile.Fields.Verified.short(dateString) + } else { + cell.checkmark.isHidden = true + cell.checkmarkPopoverString = nil } cell.delegate = configuration.profileFieldCollectionViewCellDelegate @@ -128,26 +147,10 @@ extension ProfileFieldSection { } cell.backgroundConfiguration = backgroundConfiguration } - - let noResultCellRegistration = UICollectionView.CellRegistration { cell, indexPath, item in - guard case .noResult = item else { return } - - var contentConfiguration = cell.defaultContentConfiguration() - contentConfiguration.text = L10n.Scene.Search.Searching.EmptyState.noResults // FIXME: - contentConfiguration.textProperties.alignment = .center - cell.contentConfiguration = contentConfiguration - - - var backgroundConfiguration = UIBackgroundConfiguration.listPlainCell() - backgroundConfiguration.backgroundColorTransformer = .init { _ in - return .secondarySystemBackground - } - cell.backgroundConfiguration = backgroundConfiguration - } - + let dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, item in switch item { - case .field: + case .field, .createdAt: return collectionView.dequeueConfiguredReusableCell( using: fieldCellRegistration, for: indexPath, @@ -165,12 +168,6 @@ extension ProfileFieldSection { for: indexPath, item: item ) - case .noResult: - return collectionView.dequeueConfiguredReusableCell( - using: noResultCellRegistration, - for: indexPath, - item: item - ) } } diff --git a/Mastodon/Diffable/Report/ReportSection.swift b/Mastodon/Diffable/Report/ReportSection.swift index ba3c5525a..4c8fd4345 100644 --- a/Mastodon/Diffable/Report/ReportSection.swift +++ b/Mastodon/Diffable/Report/ReportSection.swift @@ -107,6 +107,7 @@ extension ReportSection { statusView: cell.statusView ) + cell.statusView.viewModel.context = context cell.statusView.viewModel.authContext = configuration.authContext cell.configure( diff --git a/Mastodon/Diffable/Search/SearchResultSection.swift b/Mastodon/Diffable/Search/SearchResultSection.swift index 8a5d7e75f..e4dcad891 100644 --- a/Mastodon/Diffable/Search/SearchResultSection.swift +++ b/Mastodon/Diffable/Search/SearchResultSection.swift @@ -104,6 +104,7 @@ extension SearchResultSection { statusView: cell.statusView ) + cell.statusView.viewModel.context = context cell.statusView.viewModel.authContext = configuration.authContext cell.configure( diff --git a/Mastodon/Diffable/Status/StatusSection.swift b/Mastodon/Diffable/Status/StatusSection.swift index 38b8e641f..ac02273e9 100644 --- a/Mastodon/Diffable/Status/StatusSection.swift +++ b/Mastodon/Diffable/Status/StatusSection.swift @@ -27,6 +27,7 @@ extension StatusSection { static let logger = Logger(subsystem: "StatusSection", category: "logic") struct Configuration { + let context: AppContext let authContext: AuthContext weak var statusTableViewCellDelegate: StatusTableViewCellDelegate? weak var timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate? @@ -227,11 +228,7 @@ extension StatusSection { } var _snapshot = NSDiffableDataSourceSnapshot() _snapshot.appendSections([.main]) - if #available(iOS 15.0, *) { - statusView.pollTableViewDiffableDataSource?.applySnapshotUsingReloadData(_snapshot) - } else { - statusView.pollTableViewDiffableDataSource?.apply(_snapshot, animatingDifferences: false) - } + statusView.pollTableViewDiffableDataSource?.applySnapshotUsingReloadData(_snapshot) } } @@ -250,6 +247,7 @@ extension StatusSection { statusView: cell.statusView ) + cell.statusView.viewModel.context = configuration.context cell.statusView.viewModel.authContext = configuration.authContext cell.configure( @@ -277,6 +275,7 @@ extension StatusSection { statusView: cell.statusView ) + cell.statusView.viewModel.context = configuration.context cell.statusView.viewModel.authContext = configuration.authContext cell.configure( diff --git a/Mastodon/Extension/ActiveLabel.swift b/Mastodon/Extension/ActiveLabel.swift deleted file mode 100644 index 4b23d4eb3..000000000 --- a/Mastodon/Extension/ActiveLabel.swift +++ /dev/null @@ -1,66 +0,0 @@ -//extension ActiveEntity { -// -// var accessibilityLabelDescription: String { -// switch self.type { -// case .email: return L10n.Common.Controls.Status.Tag.email -// case .hashtag: return L10n.Common.Controls.Status.Tag.hashtag -// case .mention: return L10n.Common.Controls.Status.Tag.mention -// case .url: return L10n.Common.Controls.Status.Tag.url -// case .emoji: return L10n.Common.Controls.Status.Tag.emoji -// } -// } -// -// var accessibilityValueDescription: String { -// switch self.type { -// case .email(let text, _): return text -// case .hashtag(let text, _): return text -// case .mention(let text, _): return text -// case .url(_, let trimmed, _, _): return trimmed -// case .emoji(let text, _, _): return text -// } -// } -// -// func accessibilityElement(in accessibilityContainer: Any) -> ActiveLabelAccessibilityElement? { -// if case .emoji = self.type { -// return nil -// } -// -// let element = ActiveLabelAccessibilityElement(accessibilityContainer: accessibilityContainer) -// element.accessibilityTraits = .button -// element.accessibilityLabel = accessibilityLabelDescription -// element.accessibilityValue = accessibilityValueDescription -// return element -// } -//} - -//final class ActiveLabelAccessibilityElement: UIAccessibilityElement { -// var index: Int! -//} -// -// MARK: - UIAccessibilityContainer -//extension ActiveLabel { -// -// func createAccessibilityElements() -> [UIAccessibilityElement] { -// var elements: [UIAccessibilityElement] = [] -// -// let element = ActiveLabelAccessibilityElement(accessibilityContainer: self) -// element.accessibilityTraits = .staticText -// element.accessibilityLabel = accessibilityLabel -// element.accessibilityFrame = superview!.convert(frame, to: nil) -// element.accessibilityLanguage = accessibilityLanguage -// elements.append(element) -// -// for entity in activeEntities { -// guard let element = entity.accessibilityElement(in: self) else { continue } -// var glyphRange = NSRange() -// layoutManager.characterRange(forGlyphRange: entity.range, actualGlyphRange: &glyphRange) -// let rect = layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer) -// element.accessibilityFrame = self.convert(rect, to: nil) -// element.accessibilityContainer = self -// elements.append(element) -// } -// -// return elements -// } -// -//} diff --git a/Mastodon/Extension/Collection+IsNotEmpty.swift b/Mastodon/Extension/Collection+IsNotEmpty.swift new file mode 100644 index 000000000..d59b8e2fe --- /dev/null +++ b/Mastodon/Extension/Collection+IsNotEmpty.swift @@ -0,0 +1,14 @@ +// +// Array+IsNotEmpty.swift +// Mastodon +// +// Created by Marcus Kida on 01.12.22. +// + +import Foundation + +extension Collection { + var isNotEmpty: Bool { + !isEmpty + } +} diff --git a/Mastodon/Extension/UIApplication.swift b/Mastodon/Extension/UIApplication.swift index 38080fdab..74019b0ae 100644 --- a/Mastodon/Extension/UIApplication.swift +++ b/Mastodon/Extension/UIApplication.swift @@ -22,5 +22,13 @@ extension UIApplication { return version == build ? "v\(version)" : "v\(version) (\(build))" } + + func getKeyWindow() -> UIWindow? { + return UIApplication + .shared + .connectedScenes + .flatMap { ($0 as? UIWindowScene)?.windows ?? [] } + .first { $0.isKeyWindow } + } } diff --git a/Mastodon/Extension/UICollectionViewDiffableDataSource.swift b/Mastodon/Extension/UICollectionViewDiffableDataSource.swift deleted file mode 100644 index 07d2fbd12..000000000 --- a/Mastodon/Extension/UICollectionViewDiffableDataSource.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// UICollectionViewDiffableDataSource.swift -// Mastodon -// -// Created by Cirno MainasuK on 2021-10-11. -// - -import UIKit - -// ref: https://www.jessesquires.com/blog/2021/07/08/diffable-data-source-behavior-changes-and-reconfiguring-cells-in-ios-15/ -extension UICollectionViewDiffableDataSource { - func reloadData( - snapshot: NSDiffableDataSourceSnapshot, - completion: (() -> Void)? = nil - ) { - if #available(iOS 15.0, *) { - self.applySnapshotUsingReloadData(snapshot, completion: completion) - } else { - self.apply(snapshot, animatingDifferences: false, completion: completion) - } - } - - func applySnapshot( - _ snapshot: NSDiffableDataSourceSnapshot, - animated: Bool, - completion: (() -> Void)? = nil) { - - if #available(iOS 15.0, *) { - self.apply(snapshot, animatingDifferences: animated, completion: completion) - } else { - if animated { - self.apply(snapshot, animatingDifferences: true, completion: completion) - } else { - UIView.performWithoutAnimation { - self.apply(snapshot, animatingDifferences: true, completion: completion) - } - } - } - } -} diff --git a/Mastodon/Extension/UITableViewDiffableDataSource.swift b/Mastodon/Extension/UITableViewDiffableDataSource.swift deleted file mode 100644 index 5006417a4..000000000 --- a/Mastodon/Extension/UITableViewDiffableDataSource.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// UITableViewDiffableDataSource.swift -// Mastodon -// -// Created by Cirno MainasuK on 2021-10-11. -// - -import UIKit - -// ref: https://www.jessesquires.com/blog/2021/07/08/diffable-data-source-behavior-changes-and-reconfiguring-cells-in-ios-15/ -extension UITableViewDiffableDataSource { - func reloadData( - snapshot: NSDiffableDataSourceSnapshot, - completion: (() -> Void)? = nil - ) { - if #available(iOS 15.0, *) { - self.applySnapshotUsingReloadData(snapshot, completion: completion) - } else { - self.apply(snapshot, animatingDifferences: false, completion: completion) - } - } - - func applySnapshot( - _ snapshot: NSDiffableDataSourceSnapshot, - animated: Bool, - completion: (() -> Void)? = nil) { - - if #available(iOS 15.0, *) { - self.apply(snapshot, animatingDifferences: animated, completion: completion) - } else { - if animated { - self.apply(snapshot, animatingDifferences: true, completion: completion) - } else { - UIView.performWithoutAnimation { - self.apply(snapshot, animatingDifferences: true, completion: completion) - } - } - } - } -} diff --git a/Mastodon/Helper/ImageProvider.swift b/Mastodon/Helper/ImageProvider.swift new file mode 100644 index 000000000..11ea6d46e --- /dev/null +++ b/Mastodon/Helper/ImageProvider.swift @@ -0,0 +1,39 @@ +// +// ImageProvider.swift +// Mastodon +// +// Created by Jed Fox on 2022-12-03. +// + +import Foundation +import AlamofireImage +import UniformTypeIdentifiers +import UIKit + +class ImageProvider: NSObject, NSItemProviderWriting { + let url: URL + let filter: ImageFilter? + + init(url: URL, filter: ImageFilter? = nil) { + self.url = url + self.filter = filter + } + + var itemProvider: NSItemProvider { + NSItemProvider(object: self) + } + + static var writableTypeIdentifiersForItemProvider: [String] { + [UTType.png.identifier] + } + + func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, Error?) -> Void) -> Progress? { + let receipt = UIImageView.af.sharedImageDownloader.download(URLRequest(url: url), filter: filter, completion: { response in + switch response.result { + case .failure(let error): completionHandler(nil, error) + case .success(let image): completionHandler(image.pngData(), nil) + } + }) + return receipt?.request.downloadProgress + } +} diff --git a/Mastodon/Helper/URLActivityItemWithMetadata.swift b/Mastodon/Helper/URLActivityItemWithMetadata.swift new file mode 100644 index 000000000..82d1747fe --- /dev/null +++ b/Mastodon/Helper/URLActivityItemWithMetadata.swift @@ -0,0 +1,33 @@ +// +// URLActivityItemWithMetadata.swift +// Mastodon +// +// Created by Jed Fox on 2022-12-03. +// + +import UIKit +import LinkPresentation + +class URLActivityItemWithMetadata: NSObject, UIActivityItemSource { + init(url: URL, configureMetadata: (LPLinkMetadata) -> Void) { + self.url = url + self.metadata = LPLinkMetadata() + metadata.url = url + configureMetadata(metadata) + } + + let url: URL + let metadata: LPLinkMetadata + + func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any { + url + } + + func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? { + url + } + + func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? { + metadata + } +} diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift index 2747f4735..2cf6e3419 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Block.swift @@ -16,10 +16,17 @@ extension DataSourceFacade { ) async throws { let selectionFeedbackGenerator = await UISelectionFeedbackGenerator() await selectionFeedbackGenerator.selectionChanged() - - _ = try await dependency.context.apiService.toggleBlock( + + let apiService = dependency.context.apiService + let authBox = dependency.authContext.mastodonAuthenticationBox + + _ = try await apiService.toggleBlock( user: user, - authenticationBox: dependency.authContext.mastodonAuthenticationBox + authenticationBox: authBox + ) + + try await dependency.context.apiService.getBlocked( + authenticationBox: authBox ) } // end func } diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift index dd3c4903a..ca3bbd474 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift @@ -48,18 +48,12 @@ extension DataSourceFacade { assertionFailure() return } - let domain = provider.authContext.mastodonAuthenticationBox.domain - if url.host == domain, - url.pathComponents.count >= 4, - url.pathComponents[0] == "/", - url.pathComponents[1] == "web", - url.pathComponents[2] == "statuses" { - let statusID = url.pathComponents[3] - let threadViewModel = RemoteThreadViewModel(context: provider.context, authContext: provider.authContext, statusID: statusID) - _ = await provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show) - } else { - _ = await provider.coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil)) - } + + await responseToURLAction( + provider: provider, + status: status, + url: url + ) case .hashtag(_, let hashtag, _): let hashtagTimelineViewModel = HashtagTimelineViewModel(context: provider.context, authContext: provider.authContext, hashtag: hashtag) _ = await provider.coordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: provider, transition: .show) diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift index ac9da6e81..90b5b184e 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift @@ -59,8 +59,18 @@ extension DataSourceFacade { status: ManagedObjectRecord ) async throws -> UIActivityViewController { var activityItems: [Any] = try await dependency.context.managedObjectContext.perform { - guard let status = status.object(in: dependency.context.managedObjectContext) else { return [] } - return [StatusActivityItem(status: status)].compactMap { $0 } as [Any] + guard let status = status.object(in: dependency.context.managedObjectContext), + let url = URL(string: status.url ?? status.uri) + else { return [] } + return [ + URLActivityItemWithMetadata(url: url) { metadata in + metadata.title = "\(status.author.displayName) (@\(status.author.acctWithDomain))" + metadata.iconProvider = ImageProvider( + url: status.author.avatarImageURLWithFallback(domain: status.author.domain), + filter: ScaledToSizeFilter(size: CGSize.authorAvatarButtonSize) + ).itemProvider + } + ] as [Any] } var applicationActivities: [UIActivity] = [ SafariActivity(sceneCoordinator: dependency.coordinator), // open URL @@ -77,54 +87,6 @@ extension DataSourceFacade { ) return activityViewController } - - private class StatusActivityItem: NSObject, UIActivityItemSource { - init?(status: Status) { - guard let url = URL(string: status.url ?? status.uri) else { return nil } - self.url = url - self.metadata = LPLinkMetadata() - metadata.url = url - metadata.title = "\(status.author.displayName) (@\(status.author.acctWithDomain))" - metadata.iconProvider = NSItemProvider(object: IconProvider(url: status.author.avatarImageURLWithFallback(domain: status.author.domain))) - } - - let url: URL - let metadata: LPLinkMetadata - - func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any { - url - } - - func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? { - url - } - - func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? { - metadata - } - - private class IconProvider: NSObject, NSItemProviderWriting { - let url: URL - init(url: URL) { - self.url = url - } - - static var writableTypeIdentifiersForItemProvider: [String] { - [UTType.png.identifier] - } - - func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, Error?) -> Void) -> Progress? { - let filter = ScaledToSizeFilter(size: CGSize.authorAvatarButtonSize) - let receipt = UIImageView.af.sharedImageDownloader.download(URLRequest(url: url), filter: filter, completion: { response in - switch response.result { - case .failure(let error): completionHandler(nil, error) - case .success(let image): completionHandler(image.pngData(), nil) - } - }) - return receipt?.request.downloadProgress - } - } - } } // ActionToolBar @@ -155,7 +117,7 @@ extension DataSourceFacade { let composeViewModel = ComposeViewModel( context: provider.context, authContext: provider.authContext, - kind: .reply(status: status) + destination: .reply(parent: status) ) _ = provider.coordinator.present( scene: .compose(viewModel: composeViewModel), @@ -393,6 +355,18 @@ extension DataSourceFacade { alertController.addAction(cancelAction) dependency.present(alertController, animated: true) + case .translateStatus: + guard let status = menuContext.status else { return } + do { + try await DataSourceFacade.translateStatus( + provider: dependency, + status: status + ) + } catch TranslationFailure.emptyOrInvalidResponse { + let alertController = UIAlertController(title: L10n.Common.Alerts.TranslationFailed.title, message: L10n.Common.Alerts.TranslationFailed.message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: L10n.Common.Alerts.TranslationFailed.button, style: .default)) + dependency.present(alertController, animated: true) + } } } // end func } diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Translate.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Translate.swift new file mode 100644 index 000000000..8ce9c2447 --- /dev/null +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Translate.swift @@ -0,0 +1,70 @@ +// +// DataSourceFacade+Translate.swift +// Mastodon +// +// Created by Marcus Kida on 29.11.22. +// + +import UIKit +import CoreData +import CoreDataStack +import MastodonCore + +typealias Provider = UIViewController & NeedsDependency & AuthContextProvider + +extension DataSourceFacade { + enum TranslationFailure: Error { + case emptyOrInvalidResponse + } + + public static func translateStatus( + provider: Provider, + status: ManagedObjectRecord + ) async throws { + let selectionFeedbackGenerator = await UISelectionFeedbackGenerator() + await selectionFeedbackGenerator.selectionChanged() + + guard + let status = status.object(in: provider.context.managedObjectContext) + else { + return + } + + if let reblog = status.reblog { + try await translateAndApply(provider: provider, status: reblog) + } else { + try await translateAndApply(provider: provider, status: status) + } + } +} + +private extension DataSourceFacade { + static func translateStatus(provider: Provider, status: Status) async throws -> Status.TranslatedContent? { + do { + let value = try await provider.context + .apiService + .translateStatus( + statusID: status.id, + authenticationBox: provider.authContext.mastodonAuthenticationBox + ).value + + guard let content = value.content else { + throw TranslationFailure.emptyOrInvalidResponse + } + + return Status.TranslatedContent(content: content, provider: value.provider) + } catch { + throw TranslationFailure.emptyOrInvalidResponse + } + } + + static func translateAndApply(provider: Provider, status: Status) async throws { + do { + let translated = try await translateStatus(provider: provider, status: status) + status.update(translatedContent: translated) + } catch { + status.update(translatedContent: nil) + throw TranslationFailure.emptyOrInvalidResponse + } + } +} diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+URL.swift b/Mastodon/Protocol/Provider/DataSourceFacade+URL.swift new file mode 100644 index 000000000..a65de9537 --- /dev/null +++ b/Mastodon/Protocol/Provider/DataSourceFacade+URL.swift @@ -0,0 +1,32 @@ +// +// DataSourceFacade+URL.swift +// Mastodon +// +// Created by Kyle Bashour on 11/24/22. +// + +import Foundation +import CoreDataStack +import MetaTextKit +import MastodonCore + +extension DataSourceFacade { + static func responseToURLAction( + provider: DataSourceProvider & AuthContextProvider, + status: ManagedObjectRecord, + url: URL + ) async { + let domain = provider.authContext.mastodonAuthenticationBox.domain + if url.host == domain, + url.pathComponents.count >= 4, + url.pathComponents[0] == "/", + url.pathComponents[1] == "web", + url.pathComponents[2] == "statuses" { + let statusID = url.pathComponents[3] + let threadViewModel = RemoteThreadViewModel(context: provider.context, authContext: provider.authContext, statusID: statusID) + _ = await provider.coordinator.present(scene: .thread(viewModel: threadViewModel), from: nil, transition: .show) + } else { + _ = await provider.coordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil)) + } + } +} diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift index c157b7086..0b4cc3e8f 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift @@ -10,6 +10,9 @@ import CoreDataStack import MetaTextKit import MastodonCore import MastodonUI +import MastodonLocalization +import MastodonAsset +import LinkPresentation // MARK: - header extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider { @@ -120,7 +123,127 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte ) } } - + +} + +// MARK: - card +extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthContextProvider { + + func tableViewCell( + _ cell: UITableViewCell, + statusView: StatusView, + didTapCardWithURL url: URL + ) { + Task { + let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil) + guard let item = await item(from: source) else { + assertionFailure() + return + } + guard case let .status(status) = item else { + assertionFailure("only works for status data provider") + return + } + + await DataSourceFacade.responseToURLAction( + provider: self, + status: status, + url: url + ) + } + } + + func tableViewCell( + _ cell: UITableViewCell, + statusView: StatusView, + cardControl: StatusCardControl, + didTapURL url: URL + ) { + Task { + let source = DataSourceItem.Source(tableViewCell: cell, indexPath: nil) + guard let item = await item(from: source) else { + assertionFailure() + return + } + guard case let .status(status) = item else { + assertionFailure("only works for status data provider") + return + } + + await DataSourceFacade.responseToURLAction( + provider: self, + status: status, + url: url + ) + } + } + + func tableViewCell( + _ cell: UITableViewCell, + statusView: StatusView, + cardControlMenu statusCardControl: StatusCardControl + ) -> UIMenu? { + guard let card = statusView.viewModel.card, + let url = card.url else { + return nil + } + + return UIMenu(children: [ + UIAction( + title: L10n.Common.Controls.Actions.copy, + image: UIImage(systemName: "doc.on.doc") + ) { _ in + UIPasteboard.general.url = url + }, + + UIAction( + title: L10n.Common.Controls.Actions.share, + image: Asset.Arrow.squareAndArrowUp.image.withRenderingMode(.alwaysTemplate) + ) { _ in + DispatchQueue.main.async { + let activityViewController = UIActivityViewController( + activityItems: [ + URLActivityItemWithMetadata(url: url) { metadata in + metadata.title = card.title + + if let image = card.imageURL { + metadata.iconProvider = ImageProvider(url: image, filter: nil).itemProvider + } + } + ], + applicationActivities: [] + ) + self.coordinator.present( + scene: .activityViewController( + activityViewController: activityViewController, + sourceView: statusCardControl, barButtonItem: nil + ), + from: self, + transition: .activityViewControllerPresent(animated: true) + ) + } + }, + + UIAction( + title: L10n.Common.Controls.Status.Actions.shareLinkInPost, + image: Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate) + ) { _ in + DispatchQueue.main.async { + self.coordinator.present( + scene: .compose(viewModel: ComposeViewModel( + context: self.context, + authContext: self.authContext, + destination: .topLevel, + initialContent: L10n.Common.Controls.Status.linkViaUser(url.absoluteString, "@" + (statusView.viewModel.authorUsername ?? "")) + )), + from: self, + transition: .modal(animated: true) + ) + } + } + ]) + } + } // MARK: - media @@ -360,6 +483,12 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte return } + if let cell = cell as? StatusTableViewCell { + DispatchQueue.main.async { + cell.statusView.viewModel.isCurrentlyTranslating = true + } + } + try await DataSourceFacade.responseToMenuAction( dependency: self, action: action, diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift index e7b55f91c..0e0a24c9b 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift @@ -100,7 +100,7 @@ extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvid let composeViewModel = ComposeViewModel( context: self.context, authContext: authContext, - kind: .reply(status: status) + destination: .reply(parent: status) ) _ = self.coordinator.present( scene: .compose(viewModel: composeViewModel), diff --git a/Mastodon/Scene/Compose/ComposeViewController.swift b/Mastodon/Scene/Compose/ComposeViewController.swift index fbdbc7d12..9f287dbf8 100644 --- a/Mastodon/Scene/Compose/ComposeViewController.swift +++ b/Mastodon/Scene/Compose/ComposeViewController.swift @@ -34,7 +34,8 @@ final class ComposeViewController: UIViewController, NeedsDependency { return ComposeContentViewModel( context: context, authContext: viewModel.authContext, - kind: viewModel.kind + destination: viewModel.destination, + initialContent: viewModel.initialContent ) }() private(set) lazy var composeContentViewController: ComposeContentViewController = { diff --git a/Mastodon/Scene/Compose/ComposeViewModel.swift b/Mastodon/Scene/Compose/ComposeViewModel.swift index bf234b095..0dcdd9a2d 100644 --- a/Mastodon/Scene/Compose/ComposeViewModel.swift +++ b/Mastodon/Scene/Compose/ComposeViewModel.swift @@ -29,7 +29,8 @@ final class ComposeViewModel { // input let context: AppContext let authContext: AuthContext - let kind: ComposeContentViewModel.Kind + let destination: ComposeContentViewModel.Destination + let initialContent: String let traitCollectionDidChangePublisher = CurrentValueSubject(Void()) // use CurrentValueSubject to make initial event emit @@ -41,17 +42,19 @@ final class ComposeViewModel { init( context: AppContext, authContext: AuthContext, - kind: ComposeContentViewModel.Kind + destination: ComposeContentViewModel.Destination, + initialContent: String = "" ) { self.context = context self.authContext = authContext - self.kind = kind + self.destination = destination + self.initialContent = initialContent // end init self.title = { - switch kind { - case .post, .hashtag, .mention: return L10n.Scene.Compose.Title.newPost - case .reply: return L10n.Scene.Compose.Title.newReply + switch destination { + case .topLevel: return L10n.Scene.Compose.Title.newPost + case .reply: return L10n.Scene.Compose.Title.newReply } }() } diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift index 64b4d3b6a..a25dbaf1c 100644 --- a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift +++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift @@ -18,6 +18,7 @@ extension DiscoveryCommunityViewModel { tableView: tableView, context: context, configuration: StatusSection.Configuration( + context: context, authContext: authContext, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: nil, @@ -58,7 +59,7 @@ extension DiscoveryCommunityViewModel { } } - diffableDataSource.applySnapshot(snapshot, animated: false) + diffableDataSource.apply(snapshot, animatingDifferences: false) } .store(in: &disposeBag) } diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift index af8d6ff47..31b14c55d 100644 --- a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift @@ -41,7 +41,7 @@ extension DiscoveryForYouViewModel { let items = records.map { DiscoveryItem.user($0) } snapshot.appendItems(items, toSection: .forYou) - diffableDataSource.applySnapshot(snapshot, animated: false) + diffableDataSource.apply(snapshot, animatingDifferences: false) } .store(in: &disposeBag) } diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift index 11334dee8..deb8f48a7 100644 --- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift @@ -52,7 +52,7 @@ extension DiscoveryNewsViewModel { } } - diffableDataSource.applySnapshot(snapshot, animated: false) + diffableDataSource.apply(snapshot, animatingDifferences: false) } .store(in: &disposeBag) } diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift index afa0594d5..99d68796d 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift @@ -18,6 +18,7 @@ extension DiscoveryPostsViewModel { tableView: tableView, context: context, configuration: StatusSection.Configuration( + context: context, authContext: authContext, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: nil, @@ -58,7 +59,7 @@ extension DiscoveryPostsViewModel { } } - diffableDataSource.applySnapshot(snapshot, animated: false) + diffableDataSource.apply(snapshot, animatingDifferences: false) } .store(in: &disposeBag) } diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineHeaderView.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineHeaderView.swift new file mode 100644 index 000000000..3af2cf07b --- /dev/null +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineHeaderView.swift @@ -0,0 +1,173 @@ +// +// HashtagTimelineHeaderView.swift +// Mastodon +// +// Created by Marcus Kida on 22.11.22. +// + +import UIKit +import CoreDataStack +import MastodonSDK +import MastodonUI +import MastodonAsset +import MastodonLocalization + +fileprivate extension CGFloat { + static let padding: CGFloat = 16 + static let descriptionLabelSpacing: CGFloat = 12 +} + +final class HashtagTimelineHeaderView: UIView { + struct Data { + let name: String + let following: Bool + let postCount: Int + let participantsCount: Int + let postsTodayCount: Int + + static func from(_ entity: Mastodon.Entity.Tag) -> Self { + Data( + name: entity.name, + following: entity.following == true, + postCount: (entity.history ?? []).reduce(0) { res, acc in + res + (Int(acc.uses) ?? 0) + }, + participantsCount: (entity.history ?? []).reduce(0) { res, acc in + res + (Int(acc.accounts) ?? 0) + }, + postsTodayCount: Int(entity.history?.first?.uses ?? "0") ?? 0 + ) + } + + static func from(_ entity: Tag) -> Self { + Data( + name: entity.name, + following: entity.following, + postCount: entity.histories.reduce(0) { res, acc in + res + (Int(acc.uses) ?? 0) + }, + participantsCount: entity.histories.reduce(0) { res, acc in + res + (Int(acc.accounts) ?? 0) + }, + postsTodayCount: Int(entity.histories.first?.uses ?? "0") ?? 0 + ) + } + } + + let titleLabel = UILabel() + + let postCountLabel = UILabel() + let participantsLabel = UILabel() + let postsTodayLabel = UILabel() + + let postCountDescLabel = UILabel() + let participantsDescLabel = UILabel() + let postsTodayDescLabel = UILabel() + + private var widthConstraint: NSLayoutConstraint! + + var onButtonTapped: (() -> Void)? + + let followButton: UIButton = { + let button = HashtagTimelineHeaderViewActionButton() + button.cornerRadius = 10 + button.contentEdgeInsets = UIEdgeInsets(top: 6, left: 16, bottom: 5, right: 16) // set 28pt height + button.titleLabel?.font = .systemFont(ofSize: 14, weight: .bold) + return button + }() + + init() { + super.init(frame: .zero) + setupLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +private extension HashtagTimelineHeaderView { + func setupLayout() { + [titleLabel, postCountLabel, participantsLabel, postsTodayLabel, postCountDescLabel, participantsDescLabel, postsTodayDescLabel, followButton].forEach { + $0.translatesAutoresizingMaskIntoConstraints = false + addSubview($0) + } + + // hashtag name / title + titleLabel.font = UIFontMetrics(forTextStyle: .title2).scaledFont(for: .systemFont(ofSize: 22, weight: .bold)) + + [postCountLabel, participantsLabel, postsTodayLabel].forEach { + $0.font = UIFontMetrics(forTextStyle: .title3).scaledFont(for: .systemFont(ofSize: 20, weight: .bold)) + $0.text = "999" + } + + [postCountDescLabel, participantsDescLabel, postsTodayDescLabel].forEach { + $0.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .regular)) + } + + postCountDescLabel.text = L10n.Scene.FollowedTags.Header.posts + participantsDescLabel.text = L10n.Scene.FollowedTags.Header.participants + postsTodayDescLabel.text = L10n.Scene.FollowedTags.Header.postsToday + + followButton.addAction(UIAction(handler: { [weak self] _ in + self?.onButtonTapped?() + }), for: .touchUpInside) + + widthConstraint = widthAnchor.constraint(greaterThanOrEqualToConstant: 0) + + NSLayoutConstraint.activate([ + widthConstraint, + + titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: .padding), + titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: .padding), + titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -CGFloat.padding), + + postCountLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: .padding), + postCountLabel.centerXAnchor.constraint(equalTo: postCountDescLabel.centerXAnchor), + postCountDescLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor), + + participantsDescLabel.leadingAnchor.constraint(equalTo: postCountDescLabel.trailingAnchor, constant: .descriptionLabelSpacing), + participantsLabel.centerXAnchor.constraint(equalTo: participantsDescLabel.centerXAnchor), + participantsLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: .padding), + + postsTodayDescLabel.leadingAnchor.constraint(equalTo: participantsDescLabel.trailingAnchor, constant: .descriptionLabelSpacing), + postsTodayLabel.centerXAnchor.constraint(equalTo: postsTodayDescLabel.centerXAnchor), + postsTodayLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: .padding), + + postCountDescLabel.topAnchor.constraint(equalTo: postCountLabel.bottomAnchor), + participantsDescLabel.topAnchor.constraint(equalTo: participantsLabel.bottomAnchor), + postsTodayDescLabel.topAnchor.constraint(equalTo: postsTodayLabel.bottomAnchor), + + postCountDescLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -CGFloat.padding), + participantsDescLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -CGFloat.padding), + postsTodayDescLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -CGFloat.padding), + + followButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -CGFloat.padding), + followButton.bottomAnchor.constraint(equalTo: postsTodayDescLabel.bottomAnchor), + followButton.topAnchor.constraint(equalTo: postsTodayLabel.topAnchor) + ]) + } +} + +extension HashtagTimelineHeaderView { + func update(_ entity: HashtagTimelineHeaderView.Data) { + titleLabel.text = "#\(entity.name)" + followButton.setTitle(entity.following == true ? L10n.Scene.FollowedTags.Actions.unfollow : L10n.Scene.FollowedTags.Actions.follow, for: .normal) + + followButton.backgroundColor = entity.following == true ? Asset.Colors.Button.tagUnfollow.color : Asset.Colors.Button.tagFollow.color + + followButton.setTitleColor( + entity.following == true ? Asset.Colors.Button.tagFollow.color : Asset.Colors.Button.tagUnfollow.color, + for: .normal + ) + + postCountLabel.text = String(entity.postCount) + participantsLabel.text = String(entity.participantsCount) + postsTodayLabel.text = String(entity.postsTodayCount) + } + + func updateWidthConstraint(_ constant: CGFloat) { + widthConstraint.constant = constant + } +} diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineHeaderViewActionButton.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineHeaderViewActionButton.swift new file mode 100644 index 000000000..7efeb15d0 --- /dev/null +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineHeaderViewActionButton.swift @@ -0,0 +1,47 @@ +// +// HashtagTimelineHeaderViewActionButton.swift +// Mastodon +// +// Created by Marcus Kida on 25.11.22. +// + +import UIKit +import MastodonUI +import MastodonAsset + +class HashtagTimelineHeaderViewActionButton: RoundedEdgesButton { + + init() { + super.init(frame: .zero) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public override func layoutSubviews() { + super.layoutSubviews() + + let shadowColor: UIColor = { + switch traitCollection.userInterfaceStyle { + case .dark: + return .darkGray + default: + return .lightGray + } + }() + + layer.setupShadow( + color: shadowColor, + alpha: 1, + x: 0, + y: 1, + blur: 2, + spread: 0, + roundedRect: bounds, + byRoundingCorners: .allCorners, + cornerRadii: CGSize(width: cornerRadius, height: cornerRadius) + ) + } +} + diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift index 4a0be3816..75d9029e2 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift @@ -15,6 +15,7 @@ import MastodonAsset import MastodonCore import MastodonUI import MastodonLocalization +import MastodonSDK final class HashtagTimelineViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { @@ -27,6 +28,17 @@ final class HashtagTimelineViewController: UIViewController, NeedsDependency, Me var disposeBag = Set() var viewModel: HashtagTimelineViewModel! + + private lazy var headerView: HashtagTimelineHeaderView = { + let headerView = HashtagTimelineHeaderView() + headerView.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + headerView.heightAnchor.constraint(equalToConstant: 118), + ]) + + return headerView + }() let composeBarButtonItem: UIBarButtonItem = { let barButtonItem = UIBarButtonItem() @@ -114,11 +126,20 @@ extension HashtagTimelineViewController { self?.updatePromptTitle() } .store(in: &disposeBag) + + viewModel.hashtagDetails + .receive(on: DispatchQueue.main) + .sink { [weak self] tag in + guard let tag = tag else { return } + self?.updateHeaderView(with: tag) + } + .store(in: &disposeBag) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + viewModel.viewWillAppear() tableView.deselectRow(with: transitionCoordinator, animated: animated) } @@ -148,7 +169,30 @@ extension HashtagTimelineViewController { subtitle = L10n.Plural.peopleTalking(peopleTalkingNumber) } } +} +extension HashtagTimelineViewController { + private func updateHeaderView(with tag: Mastodon.Entity.Tag) { + if tableView.tableHeaderView == nil { + tableView.tableHeaderView = headerView + } + headerView.update(HashtagTimelineHeaderView.Data.from(tag)) + headerView.onButtonTapped = { [weak self] in + switch tag.following { + case .some(false): + self?.viewModel.followTag() + case .some(true): + self?.viewModel.unfollowTag() + default: + break + } + } + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + headerView.updateWidthConstraint(tableView.bounds.width) + } } extension HashtagTimelineViewController { @@ -162,10 +206,13 @@ extension HashtagTimelineViewController { @objc private func composeBarButtonItemPressed(_ sender: UIBarButtonItem) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + let hashtag = "#" + viewModel.hashtag + UITextChecker.learnWord(hashtag) let composeViewModel = ComposeViewModel( context: context, authContext: viewModel.authContext, - kind: .hashtag(hashtag: viewModel.hashtag) + destination: .topLevel, + initialContent: hashtag ) _ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil)) } diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift index 8d8b0126a..c7c0a3bd7 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel+Diffable.swift @@ -20,6 +20,7 @@ extension HashtagTimelineViewModel { tableView: tableView, context: context, configuration: StatusSection.Configuration( + context: context, authContext: authContext, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: nil, diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift index af4d2a01a..888bc720c 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewModel.swift @@ -23,7 +23,7 @@ final class HashtagTimelineViewModel { var disposeBag = Set() var needLoadMiddleIndex: Int? = nil - + // input let context: AppContext let authContext: AuthContext @@ -32,10 +32,11 @@ final class HashtagTimelineViewModel { let timelinePredicate = CurrentValueSubject(nil) let hashtagEntity = CurrentValueSubject(nil) let listBatchFetchViewModel = ListBatchFetchViewModel() - + // output var diffableDataSource: UITableViewDiffableDataSource? let didLoadLatest = PassthroughSubject() + let hashtagDetails = CurrentValueSubject(nil) // bottom loader private(set) lazy var stateMachine: GKStateMachine = { @@ -61,6 +62,7 @@ final class HashtagTimelineViewModel { domain: authContext.mastodonAuthenticationBox.domain, additionalTweetPredicate: nil ) + updateTagInformation() // end init } @@ -68,5 +70,55 @@ final class HashtagTimelineViewModel { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s:", ((#file as NSString).lastPathComponent), #line, #function) } + func viewWillAppear() { + let predicate = Tag.predicate( + domain: authContext.mastodonAuthenticationBox.domain, + name: hashtag + ) + + guard + let object = Tag.findOrFetch(in: context.managedObjectContext, matching: predicate) + else { + return hashtagDetails.send(hashtagDetails.value?.copy(following: false)) + } + + hashtagDetails.send(hashtagDetails.value?.copy(following: object.following)) + } } +extension HashtagTimelineViewModel { + func followTag() { + self.hashtagDetails.send(hashtagDetails.value?.copy(following: true)) + Task { @MainActor in + let tag = try? await context.apiService.followTag( + for: hashtag, + authenticationBox: authContext.mastodonAuthenticationBox + ).value + self.hashtagDetails.send(tag) + } + } + + func unfollowTag() { + self.hashtagDetails.send(hashtagDetails.value?.copy(following: false)) + Task { @MainActor in + let tag = try? await context.apiService.unfollowTag( + for: hashtag, + authenticationBox: authContext.mastodonAuthenticationBox + ).value + self.hashtagDetails.send(tag) + } + } +} + +private extension HashtagTimelineViewModel { + func updateTagInformation() { + Task { @MainActor in + let tag = try? await context.apiService.getTagInformation( + for: hashtag, + authenticationBox: authContext.mastodonAuthenticationBox + ).value + + self.hashtagDetails.send(tag) + } + } +} diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift index ff90775ff..8ad798165 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift @@ -122,6 +122,10 @@ extension HomeTimelineViewController { identifier: nil, options: [], children: [ + UIAction(title: "Toggle Visible Touches", image: UIImage(systemName: "hand.tap"), attributes: []) { _ in + guard let window = UIApplication.shared.getKeyWindow() as? TouchesVisibleWindow else { return } + window.touchesVisible = !window.touchesVisible + }, UIAction(title: "Toggle EmptyView", image: UIImage(systemName: "clear"), attributes: []) { [weak self] action in guard let self = self else { return } if self.emptyView.superview != nil { diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift index cabc655c9..3d59b3403 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift @@ -22,6 +22,7 @@ extension HomeTimelineViewModel { tableView: tableView, context: context, configuration: StatusSection.Configuration( + context: context, authContext: authContext, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: timelineMiddleLoaderTableViewCellDelegate, @@ -41,7 +42,7 @@ extension HomeTimelineViewModel { guard let self = self else { return } guard let diffableDataSource = self.diffableDataSource else { return } self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): incoming \(records.count) objects") - Task { + Task { @MainActor in let start = CACurrentMediaTime() defer { let end = CACurrentMediaTime() @@ -98,22 +99,22 @@ extension HomeTimelineViewModel { self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): snapshot has changes") } - guard let difference = await self.calculateReloadSnapshotDifference( + guard let difference = self.calculateReloadSnapshotDifference( tableView: tableView, oldSnapshot: oldSnapshot, newSnapshot: newSnapshot ) else { - await self.updateSnapshotUsingReloadData(snapshot: newSnapshot) + self.updateSnapshotUsingReloadData(snapshot: newSnapshot) self.didLoadLatest.send() self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): applied new snapshot") return } - await self.updateSnapshotUsingReloadData(snapshot: newSnapshot) - await tableView.scrollToRow(at: difference.targetIndexPath, at: .top, animated: false) - var contentOffset = await tableView.contentOffset - contentOffset.y = await tableView.contentOffset.y - difference.sourceDistanceToTableViewTopEdge - await tableView.setContentOffset(contentOffset, animated: false) + self.updateSnapshotUsingReloadData(snapshot: newSnapshot) + tableView.scrollToRow(at: difference.targetIndexPath, at: .top, animated: false) + var contentOffset = tableView.contentOffset + contentOffset.y = tableView.contentOffset.y - difference.sourceDistanceToTableViewTopEdge + tableView.setContentOffset(contentOffset, animated: false) self.didLoadLatest.send() self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): applied new snapshot") } // end Task @@ -130,17 +131,13 @@ extension HomeTimelineViewModel { snapshot: NSDiffableDataSourceSnapshot, animatingDifferences: Bool ) async { - diffableDataSource?.apply(snapshot, animatingDifferences: animatingDifferences) + await diffableDataSource?.apply(snapshot, animatingDifferences: animatingDifferences) } @MainActor func updateSnapshotUsingReloadData( snapshot: NSDiffableDataSourceSnapshot - ) async { - if #available(iOS 15.0, *) { - await self.diffableDataSource?.applySnapshotUsingReloadData(snapshot) - } else { - diffableDataSource?.applySnapshot(snapshot, animated: false, completion: nil) - } + ) { + self.diffableDataSource?.applySnapshotUsingReloadData(snapshot) } struct Difference { diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift index 8bf1421b1..d243c9a96 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+LoadLatestState.swift @@ -86,6 +86,8 @@ extension HomeTimelineViewModel.LoadLatestState { await enter(state: Idle.self) viewModel.homeTimelineNavigationBarTitleViewModel.receiveLoadingStateCompletion(.finished) + viewModel.context.instanceService.updateMutesAndBlocks() + // stop refresher if no new statuses let statuses = response.value let newStatuses = statuses.filter { !latestStatusIDs.contains($0.id) } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift index edd431e52..c7c967305 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift @@ -14,7 +14,6 @@ import CoreData import CoreDataStack import GameplayKit import AlamofireImage -import DateToolsSwift import MastodonCore import MastodonUI @@ -149,12 +148,7 @@ extension HomeTimelineViewModel { } // reconfigure item - if #available(iOS 15.0, *) { - snapshot.reconfigureItems([item]) - } else { - // Fallback on earlier versions - snapshot.reloadItems([item]) - } + snapshot.reconfigureItems([item]) await updateSnapshotUsingReloadData(snapshot: snapshot) // fetch data @@ -177,15 +171,10 @@ extension HomeTimelineViewModel { } // reconfigure item again - if #available(iOS 15.0, *) { - snapshot.reconfigureItems([item]) - } else { - // Fallback on earlier versions - snapshot.reloadItems([item]) - } + snapshot.reconfigureItems([item]) await updateSnapshotUsingReloadData(snapshot: snapshot) } - + } // MARK: - SuggestionAccountViewModelDelegate diff --git a/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift b/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift index 38b80fe28..7e51057bc 100644 --- a/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift +++ b/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift @@ -103,8 +103,8 @@ extension HomeTimelineNavigationBarTitleView { logoButton.setImage(Asset.Asset.mastodonTextLogo.image.withRenderingMode(.alwaysTemplate), for: .normal) logoButton.contentMode = .center logoButton.isHidden = false - logoButton.accessibilityLabel = "Logo Button" // TODO :i18n - logoButton.accessibilityHint = "Tap to scroll to top and tap again to previous location" + logoButton.accessibilityLabel = L10n.Scene.HomeTimeline.NavigationBarState.Accessibility.logoLabel // TODO :i18n + logoButton.accessibilityHint = L10n.Scene.HomeTimeline.NavigationBarState.Accessibility.logoHint case .newPostButton: configureButton( title: L10n.Scene.HomeTimeline.NavigationBarState.newPosts, diff --git a/Mastodon/Scene/MediaPreview/AltViewController.swift b/Mastodon/Scene/MediaPreview/AltViewController.swift new file mode 100644 index 000000000..05a3e5b09 --- /dev/null +++ b/Mastodon/Scene/MediaPreview/AltViewController.swift @@ -0,0 +1,92 @@ +// +// AltViewController.swift +// Mastodon +// +// Created by Jed Fox on 2022-11-26. +// + +import SwiftUI + +class AltViewController: UIViewController { + let textView = { + let textView: UITextView + + if #available(iOS 16, *) { + // TODO: update code below to use TextKit 2 when dropping iOS 15 support + textView = UITextView(usingTextLayoutManager: false) + } else { + textView = UITextView() + } + + textView.textContainer.maximumNumberOfLines = 0 + textView.textContainer.lineBreakMode = .byWordWrapping + textView.font = .preferredFont(forTextStyle: .callout) + textView.isScrollEnabled = true + textView.backgroundColor = .clear + textView.isOpaque = false + textView.isEditable = false + textView.tintColor = .white + textView.textContainerInset = UIEdgeInsets(top: 12, left: 8, bottom: 8, right: 8) + textView.contentInsetAdjustmentBehavior = .always + textView.verticalScrollIndicatorInsets.bottom = 4 + + return textView + }() + + init(alt: String, sourceView: UIView?) { + textView.text = alt + super.init(nibName: nil, bundle: nil) + self.modalPresentationStyle = .popover + self.popoverPresentationController?.delegate = self + self.popoverPresentationController?.permittedArrowDirections = .up + self.popoverPresentationController?.sourceView = sourceView + self.overrideUserInterfaceStyle = .dark + } + + @MainActor required dynamic init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + super.loadView() + view.translatesAutoresizingMaskIntoConstraints = false + } + + override func viewDidLoad() { + super.viewDidLoad() + + textView.translatesAutoresizingMaskIntoConstraints = false + view.backgroundColor = .systemBackground + view.addSubview(textView) + + textView.pinToParent() + NSLayoutConstraint.activate([ + textView.widthAnchor.constraint(lessThanOrEqualToConstant: 400), + ]) + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + UIView.performWithoutAnimation { + + let size = textView.layoutManager.boundingRect(forGlyphRange: NSMakeRange(0, (textView.textStorage.string as NSString).length), in: textView.textContainer).size + + preferredContentSize = CGSize( + width: size.width + (8 + textView.textContainer.lineFragmentPadding) * 2, + height: size.height + 12 + (textView.textContainer.lineFragmentPadding) * 2 + ) + } + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + textView.font = .preferredFont(forTextStyle: .callout) + } +} + +// MARK: UIPopoverPresentationControllerDelegate +extension AltViewController: UIPopoverPresentationControllerDelegate { + func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { + .none + } +} diff --git a/Mastodon/Scene/MediaPreview/Image/MediaPreviewImageViewController.swift b/Mastodon/Scene/MediaPreview/Image/MediaPreviewImageViewController.swift index 513110d29..68bc0219f 100644 --- a/Mastodon/Scene/MediaPreview/Image/MediaPreviewImageViewController.swift +++ b/Mastodon/Scene/MediaPreview/Image/MediaPreviewImageViewController.swift @@ -68,30 +68,21 @@ extension MediaPreviewImageViewController { let previewImageViewContextMenuInteraction = UIContextMenuInteraction(delegate: self) previewImageView.addInteraction(previewImageViewContextMenuInteraction) - switch viewModel.item { - case .remote(let imageContext): - previewImageView.imageView.accessibilityLabel = imageContext.altText - - if let thumbnail = imageContext.thumbnail { - previewImageView.imageView.image = thumbnail - previewImageView.setup(image: thumbnail, container: self.previewImageView, forceUpdate: true) - } - - previewImageView.imageView.setImage( - url: imageContext.assetURL, - placeholder: imageContext.thumbnail, - scaleToSize: nil - ) { [weak self] image in - guard let self = self else { return } - guard let image = image else { return } - self.previewImageView.setup(image: image, container: self.previewImageView, forceUpdate: true) - } - - case .local(let imageContext): - let image = imageContext.image - previewImageView.imageView.image = image - previewImageView.setup(image: image, container: previewImageView, forceUpdate: true) - + previewImageView.imageView.accessibilityLabel = viewModel.item.altText + + if let thumbnail = viewModel.item.thumbnail { + previewImageView.imageView.image = thumbnail + previewImageView.setup(image: thumbnail, container: self.previewImageView, forceUpdate: true) + } + + previewImageView.imageView.setImage( + url: viewModel.item.assetURL, + placeholder: viewModel.item.thumbnail, + scaleToSize: nil + ) { [weak self] image in + guard let self = self else { return } + guard let image = image else { return } + self.previewImageView.setup(image: image, container: self.previewImageView, forceUpdate: true) } } diff --git a/Mastodon/Scene/MediaPreview/Image/MediaPreviewImageViewModel.swift b/Mastodon/Scene/MediaPreview/Image/MediaPreviewImageViewModel.swift index e82118f78..3a4d9edd2 100644 --- a/Mastodon/Scene/MediaPreview/Image/MediaPreviewImageViewModel.swift +++ b/Mastodon/Scene/MediaPreview/Image/MediaPreviewImageViewModel.swift @@ -30,19 +30,10 @@ class MediaPreviewImageViewModel { extension MediaPreviewImageViewModel { - public enum ImagePreviewItem { - case remote(RemoteImageContext) - case local(LocalImageContext) - } - - public struct RemoteImageContext { + public struct ImagePreviewItem { let assetURL: URL? let thumbnail: UIImage? let altText: String? } - - public struct LocalImageContext { - let image: UIImage - } } diff --git a/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift b/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift index dee6c00ea..ede0be296 100644 --- a/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift +++ b/Mastodon/Scene/MediaPreview/MediaPreviewViewController.swift @@ -16,8 +16,6 @@ import MastodonLocalization final class MediaPreviewViewController: UIViewController, NeedsDependency { - static let closeButtonSize = CGSize(width: 30, height: 30) - weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } @@ -26,24 +24,23 @@ final class MediaPreviewViewController: UIViewController, NeedsDependency { let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial)) let pagingViewController = MediaPreviewPagingViewController() - - let closeButtonBackground: UIVisualEffectView = { - let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterial)) - backgroundView.alpha = 0.9 - backgroundView.layer.masksToBounds = true - backgroundView.layer.cornerRadius = MediaPreviewViewController.closeButtonSize.width * 0.5 - return backgroundView + + let topToolbar: UIStackView = { + let stackView = TouchTransparentStackView() + stackView.axis = .horizontal + stackView.distribution = .equalSpacing + stackView.alignment = .fill + stackView.translatesAutoresizingMaskIntoConstraints = false + return stackView }() - - let closeButtonBackgroundVisualEffectView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: UIBlurEffect(style: .systemUltraThinMaterial))) - - let closeButton: UIButton = { - let button = HighlightDimmableButton() - button.expandEdgeInsets = UIEdgeInsets(top: -10, left: -10, bottom: -10, right: -10) - button.imageView?.tintColor = .label + + let closeButton = HUDButton { button in button.setImage(UIImage(systemName: "xmark", withConfiguration: UIImage.SymbolConfiguration(pointSize: 16, weight: .bold))!, for: .normal) - return button - }() + } + + let altButton = HUDButton { button in + button.setTitle("ALT", for: .normal) + } deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) @@ -67,35 +64,30 @@ extension MediaPreviewViewController { visualEffectView.contentView.addSubview(pagingViewController.view) visualEffectView.pinTo(to: pagingViewController.view) pagingViewController.didMove(toParent: self) - - closeButtonBackground.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(closeButtonBackground) - NSLayoutConstraint.activate([ - closeButtonBackground.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor, constant: 12), - closeButtonBackground.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor) - ]) - closeButtonBackgroundVisualEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - closeButtonBackground.contentView.addSubview(closeButtonBackgroundVisualEffectView) - closeButton.translatesAutoresizingMaskIntoConstraints = false - closeButtonBackgroundVisualEffectView.contentView.addSubview(closeButton) + view.addSubview(topToolbar) NSLayoutConstraint.activate([ - closeButton.topAnchor.constraint(equalTo: closeButtonBackgroundVisualEffectView.topAnchor), - closeButton.leadingAnchor.constraint(equalTo: closeButtonBackgroundVisualEffectView.leadingAnchor), - closeButtonBackgroundVisualEffectView.trailingAnchor.constraint(equalTo: closeButton.trailingAnchor), - closeButtonBackgroundVisualEffectView.bottomAnchor.constraint(equalTo: closeButton.bottomAnchor), - closeButton.heightAnchor.constraint(equalToConstant: MediaPreviewViewController.closeButtonSize.height).priority(.defaultHigh), - closeButton.widthAnchor.constraint(equalToConstant: MediaPreviewViewController.closeButtonSize.width).priority(.defaultHigh), + topToolbar.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor, constant: 12), + topToolbar.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor), + topToolbar.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor), ]) - + + topToolbar.addArrangedSubview(closeButton) + NSLayoutConstraint.activate([ + closeButton.widthAnchor.constraint(equalToConstant: HUDButton.height).priority(.defaultHigh), + ]) + + topToolbar.addArrangedSubview(altButton) + viewModel.mediaPreviewImageViewControllerDelegate = self pagingViewController.interPageSpacing = 10 pagingViewController.delegate = self pagingViewController.dataSource = viewModel - closeButton.addTarget(self, action: #selector(MediaPreviewViewController.closeButtonPressed(_:)), for: .touchUpInside) - + closeButton.button.addTarget(self, action: #selector(MediaPreviewViewController.closeButtonPressed(_:)), for: .touchUpInside) + altButton.button.addTarget(self, action: #selector(MediaPreviewViewController.altButtonPressed(_:)), for: .touchUpInside) + // bind view model viewModel.$currentPage .receive(on: DispatchQueue.main) @@ -126,20 +118,34 @@ extension MediaPreviewViewController { let attachment = previewContext.attachments[index] return attachment.kind == .video // not hide buttno for audio }() - self.closeButtonBackground.isHidden = needsHideCloseButton + self.closeButton.isHidden = needsHideCloseButton default: break } } .store(in: &disposeBag) + viewModel.$altText + .receive(on: DispatchQueue.main) + .sink { [weak self] altText in + guard let self else { return } + UIView.animate(withDuration: 0.3) { + if altText == nil { + self.altButton.alpha = 0 + } else { + self.altButton.alpha = 1 + } + } + } + .store(in: &disposeBag) + viewModel.$showingChrome .receive(on: DispatchQueue.main) .removeDuplicates() .sink { [weak self] showingChrome in UIView.animate(withDuration: 0.3) { self?.setNeedsStatusBarAppearanceUpdate() - self?.closeButtonBackground.alpha = showingChrome ? 1 : 0 + self?.topToolbar.alpha = showingChrome ? 1 : 0 } } .store(in: &disposeBag) @@ -170,10 +176,14 @@ extension MediaPreviewViewController { extension MediaPreviewViewController { @objc private func closeButtonPressed(_ sender: UIButton) { - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) dismiss(animated: true, completion: nil) } - + + @objc private func altButtonPressed(_ sender: UIButton) { + guard let alt = viewModel.altText else { return } + + present(AltViewController(alt: alt, sourceView: sender), animated: true) + } } // MARK: - MediaPreviewingViewController @@ -270,19 +280,8 @@ extension MediaPreviewViewController: MediaPreviewImageViewControllerDelegate { ) { switch action { case .savePhoto: - let _savePublisher: AnyPublisher? = { - switch viewController.viewModel.item { - case .remote(let previewContext): - guard let assetURL = previewContext.assetURL else { return nil } - return context.photoLibraryService.save(imageSource: .url(assetURL)) - case .local(let previewContext): - return context.photoLibraryService.save(imageSource: .image(previewContext.image)) - } - }() - guard let savePublisher = _savePublisher else { - return - } - savePublisher + guard let assetURL = viewController.viewModel.item.assetURL else { return } + context.photoLibraryService.save(imageSource: .url(assetURL)) .sink { [weak self] completion in guard let self = self else { return } switch completion { @@ -306,20 +305,9 @@ extension MediaPreviewViewController: MediaPreviewImageViewControllerDelegate { } .store(in: &context.disposeBag) case .copyPhoto: - let _copyPublisher: AnyPublisher? = { - switch viewController.viewModel.item { - case .remote(let previewContext): - guard let assetURL = previewContext.assetURL else { return nil } - return context.photoLibraryService.copy(imageSource: .url(assetURL)) - case .local(let previewContext): - return context.photoLibraryService.copy(imageSource: .image(previewContext.image)) - } - }() - guard let copyPublisher = _copyPublisher else { - return - } + guard let assetURL = viewController.viewModel.item.assetURL else { return } - copyPublisher + context.photoLibraryService.copy(imageSource: .url(assetURL)) .sink { completion in switch completion { case .failure(let error): @@ -338,13 +326,8 @@ extension MediaPreviewViewController: MediaPreviewImageViewControllerDelegate { let activityViewController = UIActivityViewController( activityItems: { var activityItems: [Any] = [] - switch viewController.viewModel.item { - case .remote(let previewContext): - if let assetURL = previewContext.assetURL { - activityItems.append(assetURL) - } - case .local(let previewContext): - activityItems.append(previewContext.image) + if let assetURL = viewController.viewModel.item.assetURL { + activityItems.append(assetURL) } return activityItems }(), @@ -359,12 +342,12 @@ extension MediaPreviewViewController: MediaPreviewImageViewControllerDelegate { extension MediaPreviewViewController { - var closeKeyCommand: UIKeyCommand { + func closeKeyCommand(input: String) -> UIKeyCommand { UIKeyCommand( title: L10n.Scene.Preview.Keyboard.closePreview, image: nil, action: #selector(MediaPreviewViewController.closePreviewKeyCommandHandler(_:)), - input: "i", + input: input, modifierFlags: [], propertyList: nil, alternates: [], @@ -408,7 +391,8 @@ extension MediaPreviewViewController { override var keyCommands: [UIKeyCommand] { return [ - closeKeyCommand, + closeKeyCommand(input: UIKeyCommand.inputEscape), + closeKeyCommand(input: "i"), showNextKeyCommand, showPreviousKeyCommand, ] diff --git a/Mastodon/Scene/MediaPreview/MediaPreviewViewModel.swift b/Mastodon/Scene/MediaPreview/MediaPreviewViewModel.swift index 3f60b19e5..a6b604d6f 100644 --- a/Mastodon/Scene/MediaPreview/MediaPreviewViewModel.swift +++ b/Mastodon/Scene/MediaPreview/MediaPreviewViewModel.swift @@ -27,9 +27,10 @@ final class MediaPreviewViewModel: NSObject { @Published var currentPage: Int @Published var showingChrome = true - + @Published var altText: String? + // output - let viewControllers: [UIViewController] + let viewControllers: [MediaPreviewPage] private var disposeBag: Set = [] @@ -42,8 +43,11 @@ final class MediaPreviewViewModel: NSObject { self.item = item var currentPage = 0 var viewControllers: [MediaPreviewPage] = [] + var getAltText = { (page: Int) -> String? in nil } switch item { case .attachment(let previewContext): + getAltText = { previewContext.attachments[$0].altDescription } + currentPage = previewContext.initialIndex for (i, attachment) in previewContext.attachments.enumerated() { switch attachment.kind { @@ -51,11 +55,11 @@ final class MediaPreviewViewModel: NSObject { let viewController = MediaPreviewImageViewController() let viewModel = MediaPreviewImageViewModel( context: context, - item: .remote(.init( + item: .init( assetURL: attachment.assetURL.flatMap { URL(string: $0) }, thumbnail: previewContext.thumbnail(at: i), altText: attachment.altDescription - )) + ) ) viewController.viewModel = viewModel viewControllers.append(viewController) @@ -65,7 +69,8 @@ final class MediaPreviewViewModel: NSObject { context: context, item: .gif(.init( assetURL: attachment.assetURL.flatMap { URL(string: $0) }, - previewURL: attachment.previewURL.flatMap { URL(string: $0) } + previewURL: attachment.previewURL.flatMap { URL(string: $0) }, + altText: attachment.altDescription )) ) viewController.viewModel = viewModel @@ -76,7 +81,8 @@ final class MediaPreviewViewModel: NSObject { context: context, item: .video(.init( assetURL: attachment.assetURL.flatMap { URL(string: $0) }, - previewURL: attachment.previewURL.flatMap { URL(string: $0) } + previewURL: attachment.previewURL.flatMap { URL(string: $0) }, + altText: attachment.altDescription )) ) viewController.viewModel = viewModel @@ -87,11 +93,11 @@ final class MediaPreviewViewModel: NSObject { let viewController = MediaPreviewImageViewController() let viewModel = MediaPreviewImageViewModel( context: context, - item: .remote(.init( + item: .init( assetURL: previewContext.assetURL.flatMap { URL(string: $0) }, thumbnail: previewContext.thumbnail, altText: nil - )) + ) ) viewController.viewModel = viewModel viewControllers.append(viewController) @@ -99,11 +105,11 @@ final class MediaPreviewViewModel: NSObject { let viewController = MediaPreviewImageViewController() let viewModel = MediaPreviewImageViewModel( context: context, - item: .remote(.init( + item: .init( assetURL: previewContext.assetURL.flatMap { URL(string: $0) }, thumbnail: previewContext.thumbnail, altText: nil - )) + ) ) viewController.viewModel = viewModel viewControllers.append(viewController) @@ -114,6 +120,10 @@ final class MediaPreviewViewModel: NSObject { self.transitionItem = transitionItem super.init() + self.$currentPage + .map(getAltText) + .assign(to: &$altText) + for viewController in viewControllers { self.$showingChrome .sink { [weak viewController] showingChrome in diff --git a/Mastodon/Scene/MediaPreview/Video/MediaPreviewVideoViewModel.swift b/Mastodon/Scene/MediaPreview/Video/MediaPreviewVideoViewModel.swift index 97e5f955b..a6542d464 100644 --- a/Mastodon/Scene/MediaPreview/Video/MediaPreviewVideoViewModel.swift +++ b/Mastodon/Scene/MediaPreview/Video/MediaPreviewVideoViewModel.swift @@ -130,12 +130,14 @@ extension MediaPreviewVideoViewModel { struct RemoteVideoContext { let assetURL: URL? let previewURL: URL? + let altText: String? // let thumbnail: UIImage? } struct RemoteGIFContext { let assetURL: URL? let previewURL: URL? + let altText: String? } } diff --git a/Mastodon/Scene/Notification/Button/NotificationAvatarButton.swift b/Mastodon/Scene/Notification/Button/NotificationAvatarButton.swift deleted file mode 100644 index 26abfbd23..000000000 --- a/Mastodon/Scene/Notification/Button/NotificationAvatarButton.swift +++ /dev/null @@ -1,86 +0,0 @@ -// -// NotificationAvatarButton.swift -// Mastodon -// -// Created by MainasuK Cirno on 2021-7-21. -// - -import UIKit -import FLAnimatedImage -import MastodonUI - -final class NotificationAvatarButton: AvatarButton { - - // Size fixed - static let containerSize = CGSize(width: 35, height: 35) - static let badgeImageViewSize = CGSize(width: 24, height: 24) - static let badgeImageMaskSize = CGSize(width: badgeImageViewSize.width + 4, height: badgeImageViewSize.height + 4) - - let badgeImageView: UIImageView = { - let imageView = RoundedImageView() - imageView.contentMode = .center - imageView.isOpaque = true - imageView.layer.shouldRasterize = true - imageView.layer.rasterizationScale = UIScreen.main.scale - return imageView - }() - - override func _init() { - super._init() - - size = CGSize(width: 35, height: 35) - - let path: CGPath = { - let path = CGMutablePath() - path.addRect(CGRect(origin: .zero, size: NotificationAvatarButton.containerSize)) - let x: CGFloat = { - if UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft { - return -0.5 * NotificationAvatarButton.badgeImageMaskSize.width - } else { - return NotificationAvatarButton.containerSize.width - 0.5 * NotificationAvatarButton.badgeImageMaskSize.width - } - }() - path.addPath(UIBezierPath( - ovalIn: CGRect( - x: x, - y: NotificationAvatarButton.containerSize.height - 0.5 * NotificationAvatarButton.badgeImageMaskSize.width, - width: NotificationAvatarButton.badgeImageMaskSize.width, - height: NotificationAvatarButton.badgeImageMaskSize.height - ) - ).cgPath) - return path - }() - - let maskShapeLayer = CAShapeLayer() - maskShapeLayer.backgroundColor = UIColor.black.cgColor - maskShapeLayer.fillRule = .evenOdd - maskShapeLayer.path = path - avatarImageView.layer.mask = maskShapeLayer - - badgeImageView.translatesAutoresizingMaskIntoConstraints = false - addSubview(badgeImageView) - NSLayoutConstraint.activate([ - badgeImageView.centerXAnchor.constraint(equalTo: trailingAnchor), - badgeImageView.centerYAnchor.constraint(equalTo: bottomAnchor), - badgeImageView.widthAnchor.constraint(equalToConstant: NotificationAvatarButton.badgeImageViewSize.width).priority(.required - 1), - badgeImageView.heightAnchor.constraint(equalToConstant: NotificationAvatarButton.badgeImageViewSize.height).priority(.required - 1), - ]) - } - - override func updateAppearance() { - super.updateAppearance() - badgeImageView.alpha = primaryActionState.contains(.highlighted) ? 0.6 : 1.0 - } - -} - -final class RoundedImageView: UIImageView { - - override func layoutSubviews() { - super.layoutSubviews() - - layer.masksToBounds = true - layer.cornerRadius = bounds.width / 2 - layer.cornerCurve = .circular - } -} diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+Diffable.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+Diffable.swift index cb623ff15..0331f401e 100644 --- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewModel+Diffable.swift @@ -111,17 +111,13 @@ extension NotificationTimelineViewModel { snapshot: NSDiffableDataSourceSnapshot, animatingDifferences: Bool ) async { - diffableDataSource?.apply(snapshot, animatingDifferences: animatingDifferences) + await diffableDataSource?.apply(snapshot, animatingDifferences: animatingDifferences) } @MainActor func updateSnapshotUsingReloadData( snapshot: NSDiffableDataSourceSnapshot ) async { - if #available(iOS 15.0, *) { - await self.diffableDataSource?.applySnapshotUsingReloadData(snapshot) - } else { - diffableDataSource?.applySnapshot(snapshot, animated: false, completion: nil) - } + await self.diffableDataSource?.applySnapshotUsingReloadData(snapshot) } } diff --git a/Mastodon/Scene/Onboarding/Login/MastodonLoginViewController.swift b/Mastodon/Scene/Onboarding/Login/MastodonLoginViewController.swift index e9965fdde..9f9ce5d75 100644 --- a/Mastodon/Scene/Onboarding/Login/MastodonLoginViewController.swift +++ b/Mastodon/Scene/Onboarding/Login/MastodonLoginViewController.swift @@ -271,7 +271,7 @@ extension MastodonLoginViewController: MastodonLoginViewModelDelegate { snapshot.appendSections([MastodonLoginViewSection.servers]) snapshot.appendItems(viewModel.filteredServers) - dataSource?.applySnapshot(snapshot, animated: false) + dataSource?.apply(snapshot, animatingDifferences: false) OperationQueue.main.addOperation { let numberOfResults = viewModel.filteredServers.count diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift index 7e832ddca..057c742c1 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift @@ -43,11 +43,7 @@ final class MastodonPickServerViewController: UIViewController, NeedsDependency tableView.separatorStyle = .none tableView.backgroundColor = .clear tableView.keyboardDismissMode = .onDrag - if #available(iOS 15.0, *) { - tableView.sectionHeaderTopPadding = .leastNonzeroMagnitude - } else { - // Fallback on earlier versions - } + tableView.sectionHeaderTopPadding = .leastNonzeroMagnitude return tableView }() diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+Diffable.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+Diffable.swift index 7edbfd2ac..5db98c218 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+Diffable.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel+Diffable.swift @@ -24,7 +24,7 @@ extension MastodonPickServerViewModel { sectionHeaderSnapshot.appendSections([.main]) sectionHeaderSnapshot.appendItems(categoryPickerItems, toSection: .main) serverSectionHeaderView.delegate = pickServerServerSectionTableHeaderViewDelegate - serverSectionHeaderView.diffableDataSource?.applySnapshot(sectionHeaderSnapshot, animated: false) { [weak self] in + serverSectionHeaderView.diffableDataSource?.apply(sectionHeaderSnapshot, animatingDifferences: false) { [weak self] in guard let self = self else { return } guard let indexPath = self.serverSectionHeaderView.diffableDataSource?.indexPath(for: .all) else { return } self.serverSectionHeaderView.collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredHorizontally) diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift index 4f28353b0..e5ca2798a 100644 --- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift @@ -55,19 +55,10 @@ struct MastodonRegisterView: View { // Delete if viewModel.avatarImage != nil { Divider() - if #available(iOS 15.0, *) { - Button(role: .destructive) { - viewModel.avatarMediaMenuActionPublisher.send(.delete) - } label: { - Label(L10n.Scene.Register.Input.Avatar.delete, systemImage: "delete.left") - } - } else { - // Fallback on earlier ve rsions - Button { - viewModel.avatarMediaMenuActionPublisher.send(.delete) - } label: { - Label(L10n.Scene.Register.Input.Avatar.delete, systemImage: "delete.left") - } + Button(role: .destructive) { + viewModel.avatarMediaMenuActionPublisher.send(.delete) + } label: { + Label(L10n.Scene.Register.Input.Avatar.delete, systemImage: "delete.left") } } } label: { diff --git a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift index ea0b58e28..f850991f2 100644 --- a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift +++ b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController.swift @@ -37,11 +37,7 @@ final class MastodonServerRulesViewController: UIViewController, NeedsDependency tableView.separatorStyle = .none tableView.backgroundColor = .clear tableView.keyboardDismissMode = .onDrag - if #available(iOS 15.0, *) { - tableView.sectionHeaderTopPadding = 0 - } else { - // Fallback on earlier versions - } + tableView.sectionHeaderTopPadding = 0 return tableView }() diff --git a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewModel+Diffable.swift b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewModel+Diffable.swift index f6385a529..ecb868eb0 100644 --- a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewModel+Diffable.swift +++ b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewModel+Diffable.swift @@ -21,6 +21,6 @@ extension MastodonServerRulesViewModel { return ServerRuleItem.rule(ruleContext) } snapshot.appendItems(ruleItems, toSection: .rules) - diffableDataSource?.applySnapshot(snapshot, animated: false, completion: nil) + diffableDataSource?.apply(snapshot, animatingDifferences: false) } } diff --git a/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift b/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift index ee01b99e8..89d77435d 100644 --- a/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift +++ b/Mastodon/Scene/Onboarding/Share/OnboardingViewControllerAppearance.swift @@ -66,11 +66,7 @@ extension OnboardingViewControllerAppearance { navigationItem.standardAppearance = barAppearance navigationItem.compactAppearance = barAppearance navigationItem.scrollEdgeAppearance = barAppearance - if #available(iOS 15.0, *) { - navigationItem.compactScrollEdgeAppearance = barAppearance - } else { - // Fallback on earlier versions - } + navigationItem.compactScrollEdgeAppearance = barAppearance } func setupNavigationBarBackgroundView() { diff --git a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift index 241b1eacc..b0d2f3c71 100644 --- a/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift +++ b/Mastodon/Scene/Onboarding/Welcome/WelcomeViewController.swift @@ -336,11 +336,7 @@ extension WelcomeViewController: OnboardingViewControllerAppearance { navigationItem.standardAppearance = barAppearance navigationItem.compactAppearance = barAppearance navigationItem.scrollEdgeAppearance = barAppearance - if #available(iOS 15.0, *) { - navigationItem.compactScrollEdgeAppearance = barAppearance - } else { - // Fallback on earlier versions - } + navigationItem.compactScrollEdgeAppearance = barAppearance } } diff --git a/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift b/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift index 1ed76a485..171ce1ac3 100644 --- a/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift +++ b/Mastodon/Scene/Profile/About/Cell/ProfileFieldCollectionViewCell.swift @@ -58,7 +58,7 @@ extension ProfileFieldCollectionViewCell { private func _init() { // Setup colors - checkmark.tintColor = Asset.Scene.Profile.About.bioAboutFieldVerifiedCheckmark.color; + checkmark.tintColor = Asset.Scene.Profile.About.bioAboutFieldVerifiedText.color; // Setup gestures tapGesture.addTarget(self, action: #selector(ProfileFieldCollectionViewCell.didTapCheckmark(_:))) @@ -68,6 +68,11 @@ extension ProfileFieldCollectionViewCell { checkmark.addInteraction(editMenuInteraction) } + // Setup Accessibility + checkmark.isAccessibilityElement = true + checkmark.accessibilityTraits = .none + keyMetaLabel.accessibilityTraits = .none + // containerStackView: V - [ metaContainer | plainContainer ] let containerStackView = UIStackView() containerStackView.axis = .vertical diff --git a/Mastodon/Scene/Profile/About/ProfileAboutViewModel+Diffable.swift b/Mastodon/Scene/Profile/About/ProfileAboutViewModel+Diffable.swift index 0a11a71f6..eb7a6aaae 100644 --- a/Mastodon/Scene/Profile/About/ProfileAboutViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/About/ProfileAboutViewModel+Diffable.swift @@ -50,23 +50,33 @@ extension ProfileAboutViewModel { var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) diffableDataSource.apply(snapshot) - - Publishers.CombineLatest4( + + let fields = Publishers.CombineLatest3( $isEditing.removeDuplicates(), profileInfo.$fields.removeDuplicates(), - profileInfoEditing.$fields.removeDuplicates(), + profileInfoEditing.$fields.removeDuplicates() + ).map { isEditing, displayFields, editingFields in + isEditing ? editingFields : displayFields + } + + + Publishers.CombineLatest4( + $isEditing.removeDuplicates(), + $createdAt.removeDuplicates(), + fields, $emojiMeta.removeDuplicates() ) .throttle(for: 0.3, scheduler: DispatchQueue.main, latest: true) - .sink { [weak self] isEditing, displayFields, editingFields, emojiMeta in + .sink { [weak self] isEditing, createdAt, fields, emojiMeta in guard let self = self else { return } guard let diffableDataSource = self.diffableDataSource else { return } var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) - let fields: [ProfileFieldItem.FieldValue] = isEditing ? editingFields : displayFields - var items: [ProfileFieldItem] = fields.map { field in + var items: [ProfileFieldItem] = [ + .createdAt(date: createdAt), + ] + fields.map { field in if isEditing { return ProfileFieldItem.editField(field: field) } else { @@ -78,10 +88,6 @@ extension ProfileAboutViewModel { items.append(.addEntry) } - if !isEditing, items.isEmpty { - items.append(.noResult) - } - snapshot.appendItems(items, toSection: .main) diffableDataSource.apply(snapshot, animatingDifferences: false, completion: nil) diff --git a/Mastodon/Scene/Profile/About/ProfileAboutViewModel.swift b/Mastodon/Scene/Profile/About/ProfileAboutViewModel.swift index 044894b8a..8ab427c39 100644 --- a/Mastodon/Scene/Profile/About/ProfileAboutViewModel.swift +++ b/Mastodon/Scene/Profile/About/ProfileAboutViewModel.swift @@ -31,6 +31,7 @@ final class ProfileAboutViewModel { @Published var fields: [MastodonField] = [] @Published var emojiMeta: MastodonContent.Emojis = [:] + @Published var createdAt: Date = Date() init(context: AppContext) { self.context = context @@ -46,6 +47,11 @@ final class ProfileAboutViewModel { .compactMap { $0 } .flatMap { $0.publisher(for: \.fields) } .assign(to: &$fields) + + $user + .compactMap { $0 } + .flatMap { $0.publisher(for: \.createdAt) } + .assign(to: &$createdAt) Publishers.CombineLatest( $fields, diff --git a/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+Diffable.swift b/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+Diffable.swift index 69075a8ce..d52309e92 100644 --- a/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Bookmark/BookmarkViewModel+Diffable.swift @@ -17,6 +17,7 @@ extension BookmarkViewModel { tableView: tableView, context: context, configuration: StatusSection.Configuration( + context: context, authContext: authContext, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: nil, @@ -58,7 +59,7 @@ extension BookmarkViewModel { } } - diffableDataSource.applySnapshot(snapshot, animated: false) + diffableDataSource.apply(snapshot, animatingDifferences: false) } .store(in: &disposeBag) } diff --git a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift index 3723dae5d..367a4d51f 100644 --- a/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Favorite/FavoriteViewModel+Diffable.swift @@ -17,6 +17,7 @@ extension FavoriteViewModel { tableView: tableView, context: context, configuration: StatusSection.Configuration( + context: context, authContext: authContext, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: nil, @@ -58,7 +59,7 @@ extension FavoriteViewModel { } } - diffableDataSource.applySnapshot(snapshot, animated: false) + diffableDataSource.apply(snapshot, animatingDifferences: false) } .store(in: &disposeBag) } diff --git a/Mastodon/Scene/Profile/FollowedTags/FollowedTagsTableViewCell.swift b/Mastodon/Scene/Profile/FollowedTags/FollowedTagsTableViewCell.swift new file mode 100644 index 000000000..6adb15a9c --- /dev/null +++ b/Mastodon/Scene/Profile/FollowedTags/FollowedTagsTableViewCell.swift @@ -0,0 +1,78 @@ +// +// FollowedTagsTableViewCell.swift +// Mastodon +// +// Created by Marcus Kida on 24.11.22. +// + +import UIKit +import CoreDataStack + +final class FollowedTagsTableViewCell: UITableViewCell { + private var hashtagView: HashtagTimelineHeaderView! + private let separatorLine = UIView.separatorLine + private weak var viewModel: FollowedTagsViewModel? + private weak var hashtag: Tag? + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setup() + } + + required init?(coder: NSCoder) { + fatalError("Not implemented") + } + + override func prepareForReuse() { + hashtagView.removeFromSuperview() + viewModel = nil + hashtagView = nil + super.prepareForReuse() + setup() + } +} + +private extension FollowedTagsTableViewCell { + func setup() { + selectionStyle = .none + + hashtagView = HashtagTimelineHeaderView() + hashtagView.translatesAutoresizingMaskIntoConstraints = false + + contentView.addSubview(hashtagView) + contentView.backgroundColor = .clear + + NSLayoutConstraint.activate([ + hashtagView.heightAnchor.constraint(equalToConstant: 118).priority(.required), + hashtagView.topAnchor.constraint(equalTo: contentView.topAnchor), + hashtagView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + hashtagView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + hashtagView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + + 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)), + ]) + + hashtagView.onButtonTapped = { [weak self] in + guard let self = self, let tag = self.hashtag else { return } + self.viewModel?.followOrUnfollow(tag) + } + } +} + +extension FollowedTagsTableViewCell { + func populate(with tag: Tag) { + self.hashtag = tag + hashtagView.update(HashtagTimelineHeaderView.Data.from(tag)) + } + + func setup(_ viewModel: FollowedTagsViewModel) { + self.viewModel = viewModel + } +} diff --git a/Mastodon/Scene/Profile/FollowedTags/FollowedTagsViewController.swift b/Mastodon/Scene/Profile/FollowedTags/FollowedTagsViewController.swift new file mode 100644 index 000000000..9a31fe0c3 --- /dev/null +++ b/Mastodon/Scene/Profile/FollowedTags/FollowedTagsViewController.swift @@ -0,0 +1,77 @@ +// +// FollowedTagsViewController.swift +// Mastodon +// +// Created by Marcus Kida on 22.11.22. +// + +import os +import UIKit +import Combine +import MastodonAsset +import MastodonCore +import MastodonUI +import MastodonLocalization + +final class FollowedTagsViewController: UIViewController, NeedsDependency { + let logger = Logger(subsystem: String(describing: FollowedTagsViewController.self), category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var viewModel: FollowedTagsViewModel! + + let titleView = DoubleTitleLabelNavigationBarTitleView() + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.register(FollowedTagsTableViewCell.self, forCellReuseIdentifier: String(describing: FollowedTagsTableViewCell.self)) + tableView.rowHeight = UITableView.automaticDimension + 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 FollowedTagsViewController { + override func viewDidLoad() { + super.viewDidLoad() + + let _title = L10n.Scene.FollowedTags.title + title = _title + titleView.update(title: _title, subtitle: nil) + + navigationItem.titleView = titleView + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: RunLoop.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) + tableView.pinToParent() + viewModel.setupTableView(tableView) + + viewModel.presentHashtagTimeline + .receive(on: DispatchQueue.main) + .sink { [weak self] hashtagTimelineViewModel in + guard let self = self else { return } + _ = self.coordinator.present( + scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), + from: self, + transition: .show + ) + } + .store(in: &disposeBag) + } +} diff --git a/Mastodon/Scene/Profile/FollowedTags/FollowedTagsViewModel+DiffableDataSource.swift b/Mastodon/Scene/Profile/FollowedTags/FollowedTagsViewModel+DiffableDataSource.swift new file mode 100644 index 000000000..91f2cc5e9 --- /dev/null +++ b/Mastodon/Scene/Profile/FollowedTags/FollowedTagsViewModel+DiffableDataSource.swift @@ -0,0 +1,51 @@ +// +// FollowedTagsViewModel+DiffableDataSource.swift +// Mastodon +// +// Created by Marcus Kida on 01.12.22. +// + +import UIKit +import Combine +import CoreData +import CoreDataStack +import MastodonSDK +import MastodonCore + +extension FollowedTagsViewModel { + enum Section: Hashable { + case main + } + + enum Item: Hashable { + case hashtag(Tag) + } + + func tableViewDiffableDataSource( + for tableView: UITableView + ) -> UITableViewDiffableDataSource { + UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item in + switch item { + case let .hashtag(tag): + guard let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: FollowedTagsTableViewCell.self), for: indexPath) as? FollowedTagsTableViewCell else { + assertionFailure() + return UITableViewCell() + } + + cell.setup(self) + cell.populate(with: tag) + return cell + } + } + } + + func setupDiffableDataSource( + tableView: UITableView + ) { + diffableDataSource = tableViewDiffableDataSource(for: tableView) + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + diffableDataSource?.apply(snapshot) + } +} diff --git a/Mastodon/Scene/Profile/FollowedTags/FollowedTagsViewModel.swift b/Mastodon/Scene/Profile/FollowedTags/FollowedTagsViewModel.swift new file mode 100644 index 000000000..dbcf4d756 --- /dev/null +++ b/Mastodon/Scene/Profile/FollowedTags/FollowedTagsViewModel.swift @@ -0,0 +1,109 @@ +// +// FollowedTagsViewModel.swift +// Mastodon +// +// Created by Marcus Kida on 23.11.22. +// + +import os +import UIKit +import Combine +import CoreData +import CoreDataStack +import MastodonSDK +import MastodonCore + +final class FollowedTagsViewModel: NSObject { + let logger = Logger(subsystem: String(describing: FollowedTagsViewModel.self), category: "ViewModel") + var disposeBag = Set() + let fetchedResultsController: FollowedTagsFetchedResultController + + private weak var tableView: UITableView? + var diffableDataSource: UITableViewDiffableDataSource? + + // input + let context: AppContext + let authContext: AuthContext + + // output + let presentHashtagTimeline = PassthroughSubject() + + init(context: AppContext, authContext: AuthContext) { + self.context = context + self.authContext = authContext + self.fetchedResultsController = FollowedTagsFetchedResultController( + managedObjectContext: context.managedObjectContext, + domain: authContext.mastodonAuthenticationBox.domain, + user: authContext.mastodonAuthenticationBox.authenticationRecord.object(in: context.managedObjectContext)!.user + ) + + super.init() + + self.fetchedResultsController + .$records + .receive(on: DispatchQueue.main) + .sink { [weak self] records in + guard let self = self else { return } + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + snapshot.appendItems(records.map {.hashtag($0) }) + self.diffableDataSource?.apply(snapshot, animatingDifferences: true) + } + .store(in: &disposeBag) + } +} + +extension FollowedTagsViewModel { + func setupTableView(_ tableView: UITableView) { + self.tableView = tableView + setupDiffableDataSource(tableView: tableView) + tableView.delegate = self + + fetchFollowedTags() + } + + func fetchFollowedTags() { + Task { @MainActor in + try await context.apiService.getFollowedTags( + domain: authContext.mastodonAuthenticationBox.domain, + query: Mastodon.API.Account.FollowedTagsQuery(limit: nil), + authenticationBox: authContext.mastodonAuthenticationBox + ) + } + } + + func followOrUnfollow(_ tag: Tag) { + Task { @MainActor in + switch tag.following { + case true: + _ = try? await context.apiService.unfollowTag( + for: tag.name, + authenticationBox: authContext.mastodonAuthenticationBox + ) + case false: + _ = try? await context.apiService.followTag( + for: tag.name, + authenticationBox: authContext.mastodonAuthenticationBox + ) + } + fetchFollowedTags() + } + } +} + +extension FollowedTagsViewModel: 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)") + tableView.deselectRow(at: indexPath, animated: true) + + let object = fetchedResultsController.records[indexPath.row] + + let hashtagTimelineViewModel = HashtagTimelineViewModel( + context: self.context, + authContext: self.authContext, + hashtag: object.name + ) + + presentHashtagTimeline.send(hashtagTimelineViewModel) + } +} diff --git a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift index 7a30c3234..199879c83 100644 --- a/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Follower/FollowerListViewModel+Diffable.swift @@ -27,12 +27,7 @@ extension FollowerListViewModel { var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) snapshot.appendItems([.bottomLoader], toSection: .main) - if #available(iOS 15.0, *) { - diffableDataSource?.applySnapshotUsingReloadData(snapshot, completion: nil) - } else { - // Fallback on earlier versions - diffableDataSource?.apply(snapshot, animatingDifferences: false) - } + diffableDataSource?.applySnapshotUsingReloadData(snapshot, completion: nil) userFetchedResultsController.$records .receive(on: DispatchQueue.main) diff --git a/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift b/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift index e022c5736..f139a3b79 100644 --- a/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Following/FollowingListViewModel+Diffable.swift @@ -28,13 +28,8 @@ extension FollowingListViewModel { var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) snapshot.appendItems([.bottomLoader], toSection: .main) - if #available(iOS 15.0, *) { - diffableDataSource?.applySnapshotUsingReloadData(snapshot, completion: nil) - } else { - // Fallback on earlier versions - diffableDataSource?.apply(snapshot, animatingDifferences: false) - } - + diffableDataSource?.applySnapshotUsingReloadData(snapshot) + userFetchedResultsController.$records .receive(on: DispatchQueue.main) .sink { [weak self] records in diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift index 7ca819b41..55e73a1e8 100644 --- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift +++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewController.swift @@ -153,6 +153,9 @@ extension ProfileHeaderViewController { viewModel.$relationshipActionOptionSet .assign(to: \.relationshipActionOptionSet, on: profileHeaderView.viewModel) .store(in: &disposeBag) + viewModel.$isMyself + .assign(to: \.isMyself, on: profileHeaderView.viewModel) + .store(in: &disposeBag) viewModel.$isEditing .assign(to: \.isEditing, on: profileHeaderView.viewModel) .store(in: &disposeBag) diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift index c66789cca..3025907e0 100644 --- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift +++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift @@ -30,6 +30,7 @@ final class ProfileHeaderViewModel { @Published var user: MastodonUser? @Published var relationshipActionOptionSet: RelationshipActionOptionSet = .none + @Published var isMyself = false @Published var isEditing = false @Published var isUpdating = false diff --git a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift index 5095d7ac0..c5389958a 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift +++ b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView+ViewModel.swift @@ -48,6 +48,7 @@ extension ProfileHeaderView { @Published var relationshipActionOptionSet: RelationshipActionOptionSet = .none @Published var isRelationshipActionButtonHidden = false + @Published var isMyself = false init() { $relationshipActionOptionSet @@ -189,6 +190,19 @@ extension ProfileHeaderView.ViewModel { } .store(in: &disposeBag) // dashboard + $isMyself + .sink { isMyself in + if isMyself { + view.statusDashboardView.postDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.myPosts + view.statusDashboardView.followingDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.myFollowing + view.statusDashboardView.followersDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.myFollowers + } else { + view.statusDashboardView.postDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.otherPosts + view.statusDashboardView.followingDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.otherFollowing + view.statusDashboardView.followersDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.otherFollowers + } + } + .store(in: &disposeBag) $statusesCount .sink { count in let text = count.flatMap { MastodonMetricFormatter().string(from: $0) } ?? "-" diff --git a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift index cf2443552..5204cf567 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift +++ b/Mastodon/Scene/Profile/Header/View/ProfileHeaderView.swift @@ -28,7 +28,6 @@ final class ProfileHeaderView: UIView { static let avatarImageViewSize = CGSize(width: 98, height: 98) static let avatarImageViewCornerRadius: CGFloat = 25 - static let avatarImageViewBorderColor = UIColor.white static let avatarImageViewBorderWidth: CGFloat = 2 static let friendshipActionButtonSize = CGSize(width: 108, height: 34) static let bannerImageViewPlaceholderColor = UIColor.systemGray @@ -90,7 +89,6 @@ final class ProfileHeaderView: UIView { view.layer.masksToBounds = true view.layer.cornerRadius = ProfileHeaderView.avatarImageViewCornerRadius view.layer.cornerCurve = .continuous - view.layer.borderColor = ProfileHeaderView.avatarImageViewBorderColor.cgColor view.layer.borderWidth = ProfileHeaderView.avatarImageViewBorderWidth return view }() @@ -242,12 +240,13 @@ final class ProfileHeaderView: UIView { extension ProfileHeaderView { private func _init() { - backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor - ThemeService.shared.currentTheme + let currentTheme = ThemeService.shared.currentTheme + setColors(from: currentTheme.value) + + currentTheme .receive(on: DispatchQueue.main) .sink { [weak self] theme in - guard let self = self else { return } - self.backgroundColor = theme.systemBackgroundColor + self?.setColors(from: theme) } .store(in: &_disposeBag) @@ -322,10 +321,10 @@ extension ProfileHeaderView { avatarButton.translatesAutoresizingMaskIntoConstraints = false avatarImageViewBackgroundView.addSubview(avatarButton) NSLayoutConstraint.activate([ - avatarButton.topAnchor.constraint(equalTo: avatarImageViewBackgroundView.topAnchor, constant: 0.5 * ProfileHeaderView.avatarImageViewBorderWidth), - avatarButton.leadingAnchor.constraint(equalTo: avatarImageViewBackgroundView.leadingAnchor, constant: 0.5 * ProfileHeaderView.avatarImageViewBorderWidth), - avatarImageViewBackgroundView.trailingAnchor.constraint(equalTo: avatarButton.trailingAnchor, constant: 0.5 * ProfileHeaderView.avatarImageViewBorderWidth), - avatarImageViewBackgroundView.bottomAnchor.constraint(equalTo: avatarButton.bottomAnchor, constant: 0.5 * ProfileHeaderView.avatarImageViewBorderWidth), + avatarButton.topAnchor.constraint(equalTo: avatarImageViewBackgroundView.topAnchor, constant: ProfileHeaderView.avatarImageViewBorderWidth), + avatarButton.leadingAnchor.constraint(equalTo: avatarImageViewBackgroundView.leadingAnchor, constant: ProfileHeaderView.avatarImageViewBorderWidth), + avatarImageViewBackgroundView.trailingAnchor.constraint(equalTo: avatarButton.trailingAnchor, constant: ProfileHeaderView.avatarImageViewBorderWidth), + avatarImageViewBackgroundView.bottomAnchor.constraint(equalTo: avatarButton.bottomAnchor, constant: ProfileHeaderView.avatarImageViewBorderWidth), avatarButton.widthAnchor.constraint(equalToConstant: ProfileHeaderView.avatarImageViewSize.width).priority(.required - 1), avatarButton.heightAnchor.constraint(equalToConstant: ProfileHeaderView.avatarImageViewSize.height).priority(.required - 1), ]) @@ -453,6 +452,12 @@ extension ProfileHeaderView { updateLayoutMargins() } + + private func setColors(from theme: Theme) { + backgroundColor = theme.systemBackgroundColor + avatarButton.backgroundColor = theme.secondarySystemBackgroundColor + avatarImageViewBackgroundView.layer.borderColor = theme.systemBackgroundColor.cgColor + } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index ffe8bcc83..fa10bed9b 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -104,6 +104,13 @@ final class ProfileViewController: UIViewController, NeedsDependency, MediaPrevi barButtonItem.accessibilityLabel = L10n.Common.Controls.Actions.seeMore return barButtonItem }() + + private(set) lazy var followedTagsBarButtonItem: UIBarButtonItem = { + let barButtonItem = UIBarButtonItem(image: UIImage(systemName: "number"), style: .plain, target: self, action: #selector(ProfileViewController.followedTagsItemPressed(_:))) + barButtonItem.tintColor = .white + barButtonItem.accessibilityLabel = L10n.Scene.FollowedTags.title + return barButtonItem + }() let refreshControl: RefreshControl = { let refreshControl = RefreshControl() @@ -243,6 +250,11 @@ extension ProfileViewController { items.append(self.shareBarButtonItem) items.append(self.favoriteBarButtonItem) items.append(self.bookmarkBarButtonItem) + + if self.currentInstance?.canFollowTags == true { + items.append(self.followedTagsBarButtonItem) + } + return } @@ -299,6 +311,9 @@ extension ProfileViewController { viewModel.$isUpdating .assign(to: \.isUpdating, on: headerViewModel) .store(in: &disposeBag) + viewModel.relationshipViewModel.$isMyself + .assign(to: \.isMyself, on: headerViewModel) + .store(in: &disposeBag) viewModel.relationshipViewModel.$optionSet .map { $0 ?? .none } .assign(to: \.relationshipActionOptionSet, on: headerViewModel) @@ -538,13 +553,23 @@ extension ProfileViewController { @objc private func replyBarButtonItemPressed(_ sender: UIBarButtonItem) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) guard let mastodonUser = viewModel.user else { return } + let mention = "@" + mastodonUser.acct + UITextChecker.learnWord(mention) let composeViewModel = ComposeViewModel( context: context, authContext: viewModel.authContext, - kind: .mention(user: mastodonUser.asRecord) + destination: .topLevel, + initialContent: mention ) _ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil)) } + + @objc private func followedTagsItemPressed(_ sender: UIBarButtonItem) { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + + let followedTagsViewModel = FollowedTagsViewModel(context: context, authContext: viewModel.authContext) + _ = coordinator.present(scene: .followedTags(viewModel: followedTagsViewModel), from: self, transition: .show) + } @objc private func refreshControlValueChanged(_ sender: RefreshControl) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) @@ -914,3 +939,13 @@ extension ProfileViewController: PagerTabStripNavigateable { } +private extension ProfileViewController { + var currentInstance: Instance? { + guard let authenticationRecord = authContext.mastodonAuthenticationBox + .authenticationRecord + .object(in: context.managedObjectContext) + else { return nil } + + return authenticationRecord.instance + } +} diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift index 863d7b44e..67f2b8035 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+Diffable.swift @@ -18,6 +18,7 @@ extension UserTimelineViewModel { tableView: tableView, context: context, configuration: StatusSection.Configuration( + context: context, authContext: authContext, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: nil, @@ -82,7 +83,7 @@ extension UserTimelineViewModel { } } - diffableDataSource.applySnapshot(snapshot, animated: false) + diffableDataSource.apply(snapshot, animatingDifferences: false) } .store(in: &disposeBag) } diff --git a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift index acd225f0c..e843dd005 100644 --- a/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift +++ b/Mastodon/Scene/Profile/UserLIst/UserListViewModel+Diffable.swift @@ -28,13 +28,8 @@ extension UserListViewModel { var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) snapshot.appendItems([.bottomLoader], toSection: .main) - if #available(iOS 15.0, *) { - diffableDataSource?.applySnapshotUsingReloadData(snapshot, completion: nil) - } else { - // Fallback on earlier versions - diffableDataSource?.apply(snapshot, animatingDifferences: false) - } - + diffableDataSource?.applySnapshotUsingReloadData(snapshot) + // trigger initial loading stateMachine.enter(UserListViewModel.State.Reloading.self) diff --git a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewController.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewController.swift index 10e1ec3cd..3385a12ef 100644 --- a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewController.swift +++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewController.swift @@ -47,11 +47,7 @@ class ReportStatusViewController: UIViewController, NeedsDependency, ReportViewC tableView.backgroundColor = .clear tableView.keyboardDismissMode = .onDrag tableView.allowsMultipleSelection = true - if #available(iOS 15.0, *) { - tableView.sectionHeaderTopPadding = .leastNonzeroMagnitude - } else { - // Fallback on earlier versions - } + tableView.sectionHeaderTopPadding = .leastNonzeroMagnitude return tableView }() diff --git a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift index 9879863d6..fce56a2b9 100644 --- a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift +++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift @@ -65,7 +65,7 @@ extension ReportStatusViewModel { break } - diffableDataSource.applySnapshot(snapshot, animated: false) { [weak self] in + diffableDataSource.apply(snapshot, animatingDifferences: false) { [weak self] in guard let self = self else { return } guard let diffableDataSource = self.diffableDataSource else { return } diff --git a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift index 76f312273..a84a3a650 100644 --- a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift +++ b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift @@ -52,11 +52,7 @@ final class ReportSupplementaryViewController: UIViewController, NeedsDependency tableView.separatorStyle = .none tableView.backgroundColor = .clear tableView.keyboardDismissMode = .onDrag - if #available(iOS 15.0, *) { - tableView.sectionHeaderTopPadding = .leastNonzeroMagnitude - } else { - // Fallback on earlier versions - } + tableView.sectionHeaderTopPadding = .leastNonzeroMagnitude return tableView }() diff --git a/Mastodon/Scene/Report/Share/ReportViewControllerAppearance.swift b/Mastodon/Scene/Report/Share/ReportViewControllerAppearance.swift index fb9bcd63f..34d59a437 100644 --- a/Mastodon/Scene/Report/Share/ReportViewControllerAppearance.swift +++ b/Mastodon/Scene/Report/Share/ReportViewControllerAppearance.swift @@ -42,11 +42,7 @@ extension ReportViewControllerAppearance { navigationItem.standardAppearance = barAppearance navigationItem.compactAppearance = barAppearance navigationItem.scrollEdgeAppearance = barAppearance - if #available(iOS 15.0, *) { - navigationItem.compactScrollEdgeAppearance = barAppearance - } else { - // Fallback on earlier versions - } + navigationItem.compactScrollEdgeAppearance = barAppearance } func setupNavigationBarBackgroundView() { diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index 2e5d5ae58..b0af9b6d6 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -61,7 +61,7 @@ class MainTabBarController: UITabBarController { var title: String { switch self { case .home: return L10n.Common.Controls.Tabs.home - case .search: return L10n.Common.Controls.Tabs.search + case .search: return L10n.Common.Controls.Tabs.searchAndExplore case .compose: return L10n.Common.Controls.Actions.compose case .notifications: return L10n.Common.Controls.Tabs.notifications case .me: return L10n.Common.Controls.Tabs.profile @@ -379,7 +379,7 @@ extension MainTabBarController { let composeViewModel = ComposeViewModel( context: context, authContext: authContext, - kind: .post + destination: .topLevel ) _ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil)) } @@ -569,25 +569,24 @@ extension MainTabBarController: UITabBarControllerDelegate { composeButtonDidPressed(tabBarController) return false } + + // Assert index is as same as the tab rawValue. This check needs to be done `shouldSelect` + // because the nav controller has already popped in `didSelect`. + if currentTab.rawValue == tabBarController.selectedIndex, + let navigationController = viewController as? UINavigationController, + navigationController.viewControllers.count == 1, + let scrollViewContainer = navigationController.topViewController as? ScrollViewContainer { + scrollViewContainer.scrollToTop(animated: true) + } + return true } func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: select %s", ((#file as NSString).lastPathComponent), #line, #function, viewController.debugDescription) - defer { - if let tab = Tab(rawValue: viewController.tabBarItem.tag) { - currentTab = tab - } + if let tab = Tab(rawValue: viewController.tabBarItem.tag) { + currentTab = tab } - // assert index is as same as the tab rawValue - guard currentTab.rawValue == tabBarController.selectedIndex, - let navigationController = viewController as? UINavigationController, - navigationController.viewControllers.count == 1, - let scrollViewContainer = navigationController.topViewController as? ScrollViewContainer else { - return - } - - scrollViewContainer.scrollToTop(animated: true) } } @@ -804,7 +803,7 @@ extension MainTabBarController { let composeViewModel = ComposeViewModel( context: context, authContext: authContext, - kind: .post + destination: .topLevel ) _ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil)) } diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index 7c76585a6..0ffcd4c8b 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -227,7 +227,7 @@ extension SidebarViewController: UICollectionViewDelegate { let composeViewModel = ComposeViewModel( context: context, authContext: authContext, - kind: .post + destination: .topLevel ) _ = coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil)) default: diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift index c190a1a4c..e1505121d 100644 --- a/Mastodon/Scene/Search/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/Search/SearchViewController.swift @@ -135,10 +135,7 @@ extension SearchViewController { navigationItem.standardAppearance = navigationBarAppearance navigationItem.scrollEdgeAppearance = navigationBarAppearance navigationItem.compactAppearance = navigationBarAppearance - - if #available(iOS 15, *) { - navigationItem.compactScrollEdgeAppearance = navigationBarAppearance - } + navigationItem.compactScrollEdgeAppearance = navigationBarAppearance } private func setupSearchBar() { diff --git a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel+Diffable.swift b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel+Diffable.swift index c559523a7..201fa10d2 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel+Diffable.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel+Diffable.swift @@ -54,7 +54,7 @@ extension SearchHistoryViewModel { var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) snapshot.appendItems(items, toSection: .main) - diffableDataSource.apply(snapshot, animatingDifferences: false) + await diffableDataSource.apply(snapshot, animatingDifferences: false) } catch { // do nothing } diff --git a/Mastodon/Scene/Settings/Cell/SettingsToggleTableViewCell.swift b/Mastodon/Scene/Settings/Cell/SettingsToggleTableViewCell.swift index 4926dbfce..05d5ecea2 100644 --- a/Mastodon/Scene/Settings/Cell/SettingsToggleTableViewCell.swift +++ b/Mastodon/Scene/Settings/Cell/SettingsToggleTableViewCell.swift @@ -86,7 +86,7 @@ extension SettingsToggleTableViewCell { return nil default: // set tint black for Light Mode - return self.contentView.window?.tintColor ?? nil + return self.contentView.window?.tintColor } }() } diff --git a/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift b/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift index f5ac0f8ec..52d9c9f1a 100644 --- a/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift +++ b/Mastodon/Scene/Share/View/Content/DoubleTitleLabelNavigationBarTitleView.swift @@ -51,16 +51,20 @@ extension DoubleTitleLabelNavigationBarTitleView { containerView.addArrangedSubview(titleLabel) containerView.addArrangedSubview(subtitleLabel) + + isAccessibilityElement = true } func update(title: String, subtitle: String?) { titleLabel.configure(content: PlaintextMetaContent(string: title)) update(subtitle: subtitle) + accessibilityLabel = subtitle.map { "\(title), \($0)" } ?? title } func update(titleMetaContent: MetaContent, subtitle: String?) { titleLabel.configure(content: titleMetaContent) update(subtitle: subtitle) + accessibilityLabel = subtitle.map { "\(titleMetaContent.string), \($0)" } ?? titleMetaContent.string } func update(subtitle: String?) { diff --git a/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift b/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift index 334c9ce15..cbc7c61f8 100644 --- a/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift +++ b/Mastodon/Scene/Share/View/Content/PollOptionView+Configuration.swift @@ -33,12 +33,12 @@ extension PollOptionView { .store(in: &disposeBag) // percentage Publishers.CombineLatest( - option.poll.publisher(for: \.votesCount), + option.poll.publisher(for: \.votersCount), option.publisher(for: \.votesCount) ) - .map { pollVotesCount, optionVotesCount -> Double? in - guard pollVotesCount > 0, optionVotesCount >= 0 else { return 0 } - return Double(optionVotesCount) / Double(pollVotesCount) + .map { pollVotersCount, optionVotesCount -> Double? in + guard pollVotersCount > 0, optionVotesCount >= 0 else { return 0 } + return Double(optionVotesCount) / Double(pollVotersCount) } .assign(to: \.percentage, on: viewModel) .store(in: &disposeBag) diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell+ViewModel.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell+ViewModel.swift index 85184d406..2702d726b 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell+ViewModel.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell+ViewModel.swift @@ -67,6 +67,21 @@ extension StatusTableViewCell { } } .store(in: &disposeBag) + + statusView.viewModel.$card + .removeDuplicates() + .dropFirst() + .receive(on: DispatchQueue.main) + .sink { [weak tableView, weak self] _ in + guard let tableView = tableView else { return } + guard let _ = self else { return } + + UIView.performWithoutAnimation { + tableView.beginUpdates() + tableView.endUpdates() + } + } + .store(in: &disposeBag) } } diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift index c9850a0d3..b8482c564 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift @@ -86,6 +86,14 @@ extension StatusTableViewCell { self.accessibilityLabel = accessibilityLabel } .store(in: &_disposeBag) + + statusView.viewModel + .$translatedFromLanguage + .receive(on: DispatchQueue.main) + .sink(receiveValue: { [weak self] _ in + self?.invalidateIntrinsicContentSize() + }) + .store(in: &_disposeBag) } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCellDelegate.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCellDelegate.swift index 034985c03..f21e0573c 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCellDelegate.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCellDelegate.swift @@ -27,6 +27,7 @@ protocol StatusTableViewCellDelegate: AnyObject, AutoGenerateProtocolDelegate { func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, authorAvatarButtonDidPressed button: AvatarButton) func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, contentSensitiveeToggleButtonDidPressed button: UIButton) func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta) + func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, didTapCardWithURL url: URL) func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int) func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, pollTableView tableView: UITableView, didSelectRowAt indexPath: IndexPath) func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, pollVoteButtonPressed button: UIButton) @@ -36,6 +37,8 @@ protocol StatusTableViewCellDelegate: AnyObject, AutoGenerateProtocolDelegate { func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaSensitiveButtonDidPressed button: UIButton) func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, statusMetricView: StatusMetricView, reblogButtonDidPressed button: UIButton) func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, statusMetricView: StatusMetricView, favoriteButtonDidPressed button: UIButton) + func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, cardControl: StatusCardControl, didTapURL url: URL) + func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, cardControlMenu: StatusCardControl) -> UIMenu? func tableViewCell(_ cell: UITableViewCell, statusView: StatusView, accessibilityActivate: Void) // sourcery:end } @@ -61,6 +64,10 @@ extension StatusViewDelegate where Self: StatusViewContainerTableViewCell { delegate?.tableViewCell(self, statusView: statusView, metaText: metaText, didSelectMeta: meta) } + func statusView(_ statusView: StatusView, didTapCardWithURL url: URL) { + delegate?.tableViewCell(self, statusView: statusView, didTapCardWithURL: url) + } + func statusView(_ statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int) { delegate?.tableViewCell(self, statusView: statusView, mediaGridContainerView: mediaGridContainerView, mediaView: mediaView, didSelectMediaViewAt: index) } @@ -97,6 +104,14 @@ extension StatusViewDelegate where Self: StatusViewContainerTableViewCell { delegate?.tableViewCell(self, statusView: statusView, statusMetricView: statusMetricView, favoriteButtonDidPressed: button) } + func statusView(_ statusView: StatusView, cardControl: StatusCardControl, didTapURL url: URL) { + delegate?.tableViewCell(self, statusView: statusView, cardControl: cardControl, didTapURL: url) + } + + func statusView(_ statusView: StatusView, cardControlMenu: StatusCardControl) -> UIMenu? { + return delegate?.tableViewCell(self, statusView: statusView, cardControlMenu: cardControlMenu) + } + func statusView(_ statusView: StatusView, accessibilityActivate: Void) { delegate?.tableViewCell(self, statusView: statusView, accessibilityActivate: accessibilityActivate) } diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift index 350bf8660..73b700e27 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift @@ -81,6 +81,14 @@ extension StatusThreadRootTableViewCell { // a11y statusView.contentMetaText.textView.isAccessibilityElement = true statusView.contentMetaText.textView.isSelectable = true + + statusView.viewModel + .$translatedFromLanguage + .receive(on: DispatchQueue.main) + .sink(receiveValue: { [weak self] _ in + self?.invalidateIntrinsicContentSize() + }) + .store(in: &disposeBag) } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { diff --git a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel+Diffable.swift b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel+Diffable.swift index 35ba305bc..afb3eb7ec 100644 --- a/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel+Diffable.swift +++ b/Mastodon/Scene/SuggestionAccount/SuggestionAccountViewModel+Diffable.swift @@ -34,12 +34,7 @@ extension SuggestionAccountViewModel { let items: [RecommendAccountItem] = records.map { RecommendAccountItem.account($0) } snapshot.appendItems(items, toSection: .main) - if #available(iOS 15.0, *) { - tableViewDiffableDataSource.applySnapshotUsingReloadData(snapshot, completion: nil) - } else { - // Fallback on earlier versions - tableViewDiffableDataSource.applySnapshot(snapshot, animated: false, completion: nil) - } + tableViewDiffableDataSource.applySnapshotUsingReloadData(snapshot, completion: nil) } .store(in: &disposeBag) } @@ -71,13 +66,7 @@ extension SuggestionAccountViewModel { } snapshot.appendItems(items, toSection: .main) - - if #available(iOS 15.0, *) { - collectionViewDiffableDataSource.applySnapshotUsingReloadData(snapshot, completion: nil) - } else { - // Fallback on earlier versions - collectionViewDiffableDataSource.applySnapshot(snapshot, animated: false, completion: nil) - } + collectionViewDiffableDataSource.applySnapshotUsingReloadData(snapshot, completion: nil) } .store(in: &disposeBag) } diff --git a/Mastodon/Scene/Thread/ThreadViewController.swift b/Mastodon/Scene/Thread/ThreadViewController.swift index e8e6ce130..1b386aa6a 100644 --- a/Mastodon/Scene/Thread/ThreadViewController.swift +++ b/Mastodon/Scene/Thread/ThreadViewController.swift @@ -117,7 +117,7 @@ extension ThreadViewController { let composeViewModel = ComposeViewModel( context: context, authContext: viewModel.authContext, - kind: .reply(status: threadContext.status) + destination: .reply(parent: threadContext.status) ) _ = coordinator.present( scene: .compose(viewModel: composeViewModel), diff --git a/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift b/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift index 834d478e6..850c6bab2 100644 --- a/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift +++ b/Mastodon/Scene/Thread/ThreadViewModel+Diffable.swift @@ -24,6 +24,7 @@ extension ThreadViewModel { tableView: tableView, context: context, configuration: StatusSection.Configuration( + context: context, authContext: authContext, statusTableViewCellDelegate: statusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: nil, @@ -153,17 +154,13 @@ extension ThreadViewModel { snapshot: NSDiffableDataSourceSnapshot, animatingDifferences: Bool ) async { - diffableDataSource?.apply(snapshot, animatingDifferences: animatingDifferences) + await diffableDataSource?.apply(snapshot, animatingDifferences: animatingDifferences) } @MainActor func updateSnapshotUsingReloadData( snapshot: NSDiffableDataSourceSnapshot ) async { - if #available(iOS 15.0, *) { - await self.diffableDataSource?.applySnapshotUsingReloadData(snapshot) - } else { - diffableDataSource?.applySnapshot(snapshot, animated: false, completion: nil) - } + await self.diffableDataSource?.applySnapshotUsingReloadData(snapshot) } // Some UI tweaks to present replies and conversation smoothly diff --git a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift index a436fa1b3..ce9cfca96 100644 --- a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift +++ b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift @@ -81,8 +81,8 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { transitionItem.transitionView = transitionImageView transitionContext.containerView.addSubview(transitionImageView) - toVC.closeButtonBackground.alpha = 0 - + toVC.topToolbar.alpha = 0 + if UIAccessibility.isReduceTransparencyEnabled { toVC.visualEffectView.alpha = 0 } @@ -101,7 +101,7 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { toVC.pagingViewController.view.alpha = 1 transitionImageView.removeFromSuperview() UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseInOut]) { - toVC.closeButtonBackground.alpha = 1 + toVC.topToolbar.alpha = 1 } transitionContext.completeTransition(position == .end) } @@ -138,13 +138,13 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { } } - // update close button + // update top toolbar UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseInOut]) { - fromVC.closeButtonBackground.alpha = 0 + fromVC.topToolbar.alpha = 0 } animator.addCompletion { position in UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseInOut]) { - fromVC.closeButtonBackground.alpha = position == .end ? 0 : 1 + fromVC.topToolbar.alpha = position == .end ? 0 : 1 } } @@ -202,7 +202,7 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { mediaPreviewTransitionContext.snapshot.contentMode = .scaleAspectFill mediaPreviewTransitionContext.snapshot.clipsToBounds = true transitionMaskView.addSubview(mediaPreviewTransitionContext.snapshot) - fromVC.view.bringSubviewToFront(fromVC.closeButtonBackground) + fromVC.view.bringSubviewToFront(fromVC.topToolbar) transitionItem.transitionView = mediaPreviewTransitionContext.transitionView transitionItem.snapshotTransitioning = mediaPreviewTransitionContext.snapshot @@ -517,7 +517,7 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { let scaleTransform = CGAffineTransform(scaleX: (itemWidth / size.width), y: (itemHeight / size.height)) let scaledOffset = transitionItem.touchOffset.apply(transform: scaleTransform) - let center = transitionView.convert(transitionView.center, to: nil) + let center = transitionView.convert(CGPoint(x: transitionView.bounds.midX, y: transitionView.bounds.midY), to: nil) snapshot.center = (center + (translation + (transitionItem.touchOffset - scaledOffset))).point snapshot.bounds = CGRect(origin: CGPoint.zero, size: CGSize(width: itemWidth, height: itemHeight)) transitionItem.touchOffset = scaledOffset diff --git a/Mastodon/Supporting Files/SceneDelegate.swift b/Mastodon/Supporting Files/SceneDelegate.swift index 4476477fd..e2f045a7b 100644 --- a/Mastodon/Supporting Files/SceneDelegate.swift +++ b/Mastodon/Supporting Files/SceneDelegate.swift @@ -11,6 +11,7 @@ import Combine import CoreDataStack import MastodonCore import MastodonExtension +import MastodonUI #if PROFILE import FPSIndicator @@ -35,8 +36,13 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = scene as? UIWindowScene else { return } + #if DEBUG + let window = TouchesVisibleWindow(windowScene: windowScene) + self.window = window + #else let window = UIWindow(windowScene: windowScene) self.window = window + #endif // set tint color window.tintColor = UIColor.label @@ -112,6 +118,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // trigger authenticated user account update AppContext.shared.authenticationService.updateActiveUserAccountPublisher.send() + + // update mutes and blocks and remove related data + AppContext.shared.instanceService.updateMutesAndBlocks() if let shortcutItem = savedShortCutItem { Task { @@ -185,7 +194,7 @@ extension SceneDelegate { let composeViewModel = ComposeViewModel( context: AppContext.shared, authContext: authContext, - kind: .post + destination: .topLevel ) _ = coordinator?.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil)) logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): present compose scene") diff --git a/Mastodon/Template/AutoGenerateProtocolDelegate.swifttemplate b/Mastodon/Template/AutoGenerateProtocolDelegate.swifttemplate index 47eb4ce19..e8677d970 100644 --- a/Mastodon/Template/AutoGenerateProtocolDelegate.swifttemplate +++ b/Mastodon/Template/AutoGenerateProtocolDelegate.swifttemplate @@ -1,3 +1,17 @@ +<% +func methodDeclaration(_ method: SourceryRuntime.Method, newName: String) -> String { + var result = newName + if method.throws { + result = result + " throws" + } else if method.rethrows { + result = result + " rethrows" + } + if method.returnTypeName.isVoid { + return result + } + return result + " -> \(method.returnTypeName)" +} +-%> <% for type in types.implementing["AutoGenerateProtocolDelegate"] { guard let replaceOf = type.annotations["replaceOf"] as? String else { continue } guard let replaceWith = type.annotations["replaceWith"] as? String else { continue } @@ -5,7 +19,7 @@ guard let aProtocol = types.protocols.first(where: { $0.name == protocolToGenerate }) else { continue } -%> // sourcery:inline:<%= type.name %>.AutoGenerateProtocolDelegate <% for method in aProtocol.methods { -%> -<%= method.name.replacingOccurrences(of: replaceOf, with: replaceWith) %> +<%= methodDeclaration(method, newName: method.name.replacingOccurrences(of: replaceOf, with: replaceWith)) %> <% } -%> // sourcery:end <% } %> diff --git a/Mastodon/Template/AutoGenerateProtocolRelayDelegate.swifttemplate b/Mastodon/Template/AutoGenerateProtocolRelayDelegate.swifttemplate index b57f26038..d2b0dd58c 100644 --- a/Mastodon/Template/AutoGenerateProtocolRelayDelegate.swifttemplate +++ b/Mastodon/Template/AutoGenerateProtocolRelayDelegate.swifttemplate @@ -6,6 +6,9 @@ func methodDeclaration(_ method: SourceryRuntime.Method) -> String { } else if method.rethrows { result = result + " rethrows" } + if method.returnTypeName.isVoid { + return result + } return result + " -> \(method.returnTypeName)" } -%> @@ -42,7 +45,7 @@ func methodCall( guard let aProtocol = types.protocols.first(where: { $0.name == protocolToGenerate }) else { continue } -%> // sourcery:inline:<%= type.name %>.AutoGenerateProtocolRelayDelegate <% for method in aProtocol.methods { -%> -func <%= method.name -%> { +func <%= methodDeclaration(method) -%> { <%= methodCall(method, replaceOf: replaceOf, replaceWith: replaceWith) %> } diff --git a/MastodonIntent/ca.lproj/Intents.strings b/MastodonIntent/ca.lproj/Intents.strings index 6b92eb263..c02ac08cf 100644 --- a/MastodonIntent/ca.lproj/Intents.strings +++ b/MastodonIntent/ca.lproj/Intents.strings @@ -22,7 +22,7 @@ "ZbSjzC" = "Visibilitat"; -"Zo4jgJ" = "Visibilitat de la Publicació"; +"Zo4jgJ" = "Visibilitat de la publicació"; "apSxMG-dYQ5NN" = "Hi ha ${count} opcions que coincideixen amb ‘Públic’."; @@ -30,9 +30,9 @@ "ayoYEb-dYQ5NN" = "${content}, Públic"; -"ayoYEb-ehFLjY" = "${content}, Només Seguidors"; +"ayoYEb-ehFLjY" = "${content}, Només seguidors"; -"dUyuGg" = "Publicació"; +"dUyuGg" = "Publica a Mastodon"; "dYQ5NN" = "Públic"; diff --git a/MastodonIntent/de.lproj/Intents.strings b/MastodonIntent/de.lproj/Intents.strings index fd3fbd40f..5d0056766 100644 --- a/MastodonIntent/de.lproj/Intents.strings +++ b/MastodonIntent/de.lproj/Intents.strings @@ -1,12 +1,12 @@ -"16wxgf" = "Auf Mastodon posten"; +"16wxgf" = "Auf Mastodon veröffentlichen"; "751xkl" = "Textinhalt"; -"CsR7G2" = "Auf Mastodon posten"; +"CsR7G2" = "Auf Mastodon veröffentlichen"; -"HZSGTr" = "Welcher Inhalt soll gepostet werden?"; +"HZSGTr" = "Welcher Inhalt soll veröffentlicht werden?"; -"HdGikU" = "Posten fehlgeschlagen"; +"HdGikU" = "Veröffentlichen fehlgeschlagen"; "KDNTJ4" = "Fehlerursache"; diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index 1ac22e6a7..32dbfb2c8 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -3,25 +3,35 @@ import PackageDescription +let publicLibraryTargets = [ + "CoreDataStack", + "MastodonAsset", + "MastodonCommon", + "MastodonCore", + "MastodonExtension", + "MastodonLocalization", + "MastodonSDK", + "MastodonUI", +] + let package = Package( name: "MastodonSDK", defaultLocalization: "en", platforms: [ - .iOS(.v14), + .iOS(.v15), ], products: [ + // Static Library .library( name: "MastodonSDK", - targets: [ - "CoreDataStack", - "MastodonAsset", - "MastodonCommon", - "MastodonCore", - "MastodonExtension", - "MastodonLocalization", - "MastodonSDK", - "MastodonUI", - ]) + targets: publicLibraryTargets + ), + // Dynamic Library + .library( + name: "MastodonSDKDynamic", + type: .dynamic, + targets: publicLibraryTargets + ) ], dependencies: [ .package(name: "ArkanaKeys", path: "../dependencies/ArkanaKeys"), diff --git a/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/.xccurrentversion b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/.xccurrentversion index 1d5ea989f..b2d4c7f6e 100644 --- a/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/.xccurrentversion +++ b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - CoreData 4.xcdatamodel + CoreData 7.xcdatamodel diff --git a/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 5.xcdatamodel/contents b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 5.xcdatamodel/contents new file mode 100644 index 000000000..9f07cca78 --- /dev/null +++ b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 5.xcdatamodel/contents @@ -0,0 +1,258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 6.xcdatamodel/contents b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 6.xcdatamodel/contents new file mode 100644 index 000000000..30e89ccb4 --- /dev/null +++ b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 6.xcdatamodel/contents @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 7.xcdatamodel/contents b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 7.xcdatamodel/contents new file mode 100644 index 000000000..7198c75c6 --- /dev/null +++ b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 7.xcdatamodel/contents @@ -0,0 +1,278 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Card.swift b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Card.swift new file mode 100644 index 000000000..64f5e2120 --- /dev/null +++ b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Card.swift @@ -0,0 +1,180 @@ +// +// Card.swift +// CoreDataStack +// +// Created by Kyle Bashour on 11/23/22. +// + +import Foundation +import CoreData + +public final class Card: NSManagedObject { + // sourcery: autoGenerateProperty + @NSManaged public private(set) var urlRaw: String + public var url: URL? { + URL(string: urlRaw) + } + + // sourcery: autoGenerateProperty + @NSManaged public private(set) var title: String + // sourcery: autoGenerateProperty + @NSManaged public private(set) var desc: String + + @NSManaged public private(set) var typeRaw: String + // sourcery: autoGenerateProperty + public var type: MastodonCardType { + get { MastodonCardType(rawValue: typeRaw) } + set { typeRaw = newValue.rawValue } + } + + // sourcery: autoGenerateProperty + @NSManaged public private(set) var authorName: String? + // sourcery: autoGenerateProperty + @NSManaged public private(set) var authorURLRaw: String? + // sourcery: autoGenerateProperty + @NSManaged public private(set) var providerName: String? + // sourcery: autoGenerateProperty + @NSManaged public private(set) var providerURLRaw: String? + // sourcery: autoGenerateProperty + @NSManaged public private(set) var width: Int64 + // sourcery: autoGenerateProperty + @NSManaged public private(set) var height: Int64 + // sourcery: autoGenerateProperty + @NSManaged public private(set) var image: String? + public var imageURL: URL? { + image.flatMap(URL.init) + } + + // sourcery: autoGenerateProperty + @NSManaged public private(set) var embedURLRaw: String? + // sourcery: autoGenerateProperty + @NSManaged public private(set) var blurhash: String? + // sourcery: autoGenerateProperty + @NSManaged public private(set) var html: String? + + // sourcery: autoGenerateRelationship + @NSManaged public private(set) var status: Status +} + +extension Card { + + @discardableResult + public static func insert( + into context: NSManagedObjectContext, + property: Property + ) -> Card { + let object: Card = context.insertObject() + + object.configure(property: property) + + return object + } + +} + +extension Card: Managed { + public static var defaultSortDescriptors: [NSSortDescriptor] { + return [] + } +} + +// MARK: - AutoGenerateProperty +extension Card: AutoGenerateProperty { + // sourcery:inline:Card.AutoGenerateProperty + + // Generated using Sourcery + // DO NOT EDIT + public struct Property { + public let urlRaw: String + public let title: String + public let desc: String + public let type: MastodonCardType + public let authorName: String? + public let authorURLRaw: String? + public let providerName: String? + public let providerURLRaw: String? + public let width: Int64 + public let height: Int64 + public let image: String? + public let embedURLRaw: String? + public let blurhash: String? + public let html: String? + + public init( + urlRaw: String, + title: String, + desc: String, + type: MastodonCardType, + authorName: String?, + authorURLRaw: String?, + providerName: String?, + providerURLRaw: String?, + width: Int64, + height: Int64, + image: String?, + embedURLRaw: String?, + blurhash: String?, + html: String? + ) { + self.urlRaw = urlRaw + self.title = title + self.desc = desc + self.type = type + self.authorName = authorName + self.authorURLRaw = authorURLRaw + self.providerName = providerName + self.providerURLRaw = providerURLRaw + self.width = width + self.height = height + self.image = image + self.embedURLRaw = embedURLRaw + self.blurhash = blurhash + self.html = html + } + } + + public func configure(property: Property) { + self.urlRaw = property.urlRaw + self.title = property.title + self.desc = property.desc + self.type = property.type + self.authorName = property.authorName + self.authorURLRaw = property.authorURLRaw + self.providerName = property.providerName + self.providerURLRaw = property.providerURLRaw + self.width = property.width + self.height = property.height + self.image = property.image + self.embedURLRaw = property.embedURLRaw + self.blurhash = property.blurhash + self.html = property.html + } + + public func update(property: Property) { + } + + // sourcery:end +} + +// MARK: - AutoGenerateRelationship +extension Card: AutoGenerateRelationship { + // sourcery:inline:Card.AutoGenerateRelationship + + // Generated using Sourcery + // DO NOT EDIT + public struct Relationship { + public let status: Status + + public init( + status: Status + ) { + self.status = status + } + } + + public func configure(relationship: Relationship) { + self.status = relationship.status + } + + // sourcery:end +} diff --git a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Instance.swift b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Instance.swift index 8976097ef..c11a92b76 100644 --- a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Instance.swift +++ b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Instance.swift @@ -10,12 +10,14 @@ import CoreData public final class Instance: NSManagedObject { @NSManaged public var domain: String - + @NSManaged public var version: String? + @NSManaged public private(set) var createdAt: Date @NSManaged public private(set) var updatedAt: Date @NSManaged public private(set) var configurationRaw: Data? - + @NSManaged public private(set) var configurationV2Raw: Data? + // MARK: one-to-many relationships @NSManaged public var authentications: Set } @@ -35,6 +37,7 @@ extension Instance { ) -> Instance { let instance: Instance = context.insertObject() instance.domain = property.domain + instance.version = property.version return instance } @@ -42,6 +45,10 @@ extension Instance { self.configurationRaw = configurationRaw } + public func update(configurationV2Raw: Data?) { + self.configurationV2Raw = configurationV2Raw + } + public func didUpdate(at networkDate: Date) { self.updatedAt = networkDate } @@ -50,9 +57,11 @@ extension Instance { extension Instance { public struct Property { public let domain: String - - public init(domain: String) { + public let version: String? + + public init(domain: String, version: String?) { self.domain = domain + self.version = version } } } diff --git a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/MastodonUser.swift b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/MastodonUser.swift index 760985d68..fe668ccb9 100644 --- a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/MastodonUser.swift +++ b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/MastodonUser.swift @@ -77,6 +77,7 @@ final public class MastodonUser: NSManagedObject { @NSManaged public private(set) var votePollOptions: Set @NSManaged public private(set) var votePolls: Set // relationships + @NSManaged public private(set) var followedTags: Set @NSManaged public private(set) var following: Set @NSManaged public private(set) var followingBy: Set @NSManaged public private(set) var followRequested: Set diff --git a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift index 0c7291913..08f58ca3f 100644 --- a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift +++ b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift @@ -11,6 +11,16 @@ import Foundation public final class Status: NSManagedObject { public typealias ID = String + public class TranslatedContent: NSObject { + public let content: String + public let provider: String? + + public init(content: String, provider: String?) { + self.content = content + self.provider = provider + } + } + // sourcery: autoGenerateProperty @NSManaged public private(set) var identifier: ID // sourcery: autoGenerateProperty @@ -84,7 +94,9 @@ public final class Status: NSManagedObject { @NSManaged public private(set) var pinnedBy: MastodonUser? // sourcery: autoGenerateRelationship @NSManaged public private(set) var poll: Poll? - + // sourcery: autoGenerateRelationship + @NSManaged public private(set) var card: Card? + // one-to-many relationship @NSManaged public private(set) var feeds: Set @@ -99,6 +111,9 @@ public final class Status: NSManagedObject { @NSManaged public private(set) var deletedAt: Date? // sourcery: autoUpdatableObject @NSManaged public private(set) var revealedAt: Date? + + // sourcery: autoUpdatableObject + @NSManaged public private(set) var translatedContent: TranslatedContent? } extension Status { @@ -379,15 +394,18 @@ extension Status: AutoGenerateRelationship { public let author: MastodonUser public let reblog: Status? public let poll: Poll? + public let card: Card? public init( author: MastodonUser, reblog: Status?, - poll: Poll? + poll: Poll?, + card: Card? ) { self.author = author self.reblog = reblog self.poll = poll + self.card = card } } @@ -395,6 +413,7 @@ extension Status: AutoGenerateRelationship { self.author = relationship.author self.reblog = relationship.reblog self.poll = relationship.poll + self.card = relationship.card } // sourcery:end } @@ -495,6 +514,11 @@ extension Status: AutoUpdatableObject { self.revealedAt = revealedAt } } + public func update(translatedContent: TranslatedContent?) { + if self.translatedContent != translatedContent { + self.translatedContent = translatedContent + } + } public func update(attachments: [MastodonAttachment]) { if self.attachments != attachments { self.attachments = attachments diff --git a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Tag.swift b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Tag.swift index b5c335db3..8332f3d4c 100644 --- a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Tag.swift +++ b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Tag.swift @@ -24,10 +24,13 @@ public final class Tag: NSManagedObject { @NSManaged public private(set) var name: String // sourcery: autoUpdatableObject, autoGenerateProperty @NSManaged public private(set) var url: String - + // sourcery: autoUpdatableObject, autoGenerateProperty + @NSManaged public private(set) var following: Bool + // one-to-one relationship // many-to-many relationship + @NSManaged public private(set) var followedBy: Set // one-to-many relationship @NSManaged public private(set) var searchHistories: Set @@ -88,7 +91,16 @@ public extension Tag { } static func predicate(name: String) -> NSPredicate { - NSPredicate(format: "%K == %@", #keyPath(Tag.name), name) + // use case-insensitive query as tags #CaN #BE #speLLed #USiNG #arbITRARy #cASe + NSPredicate(format: "%K MATCHES[c] %@", #keyPath(Tag.name), name) + } + + static func predicate(domain: String, following: Bool) -> NSPredicate { + NSPredicate(format: "%K == %@ AND %K == %d", #keyPath(Tag.domain), domain, #keyPath(Tag.following), following) + } + + static func predicate(followedBy user: MastodonUser) -> NSPredicate { + NSPredicate(format: "ANY %K.%K == %@", #keyPath(Tag.followedBy), #keyPath(MastodonUser.id), user.id) } static func predicate(domain: String, name: String) -> NSPredicate { @@ -97,6 +109,13 @@ public extension Tag { predicate(name: name), ]) } + + static func predicate(domain: String, following: Bool, by user: MastodonUser) -> NSPredicate { + NSCompoundPredicate(andPredicateWithSubpredicates: [ + predicate(domain: domain, following: following), + predicate(followedBy: user) + ]) + } } // MARK: - AutoGenerateProperty @@ -112,6 +131,7 @@ extension Tag: AutoGenerateProperty { public let updatedAt: Date public let name: String public let url: String + public let following: Bool public let histories: [MastodonTagHistory] public init( @@ -121,6 +141,7 @@ extension Tag: AutoGenerateProperty { updatedAt: Date, name: String, url: String, + following: Bool, histories: [MastodonTagHistory] ) { self.identifier = identifier @@ -129,6 +150,7 @@ extension Tag: AutoGenerateProperty { self.updatedAt = updatedAt self.name = name self.url = url + self.following = following self.histories = histories } } @@ -140,12 +162,14 @@ extension Tag: AutoGenerateProperty { self.updatedAt = property.updatedAt self.name = property.name self.url = property.url + self.following = property.following self.histories = property.histories } public func update(property: Property) { update(updatedAt: property.updatedAt) update(url: property.url) + update(following: property.following) update(histories: property.histories) } // sourcery:end @@ -167,12 +191,30 @@ extension Tag: AutoUpdatableObject { self.url = url } } + public func update(following: Bool) { + if self.following != following { + self.following = following + } + } public func update(histories: [MastodonTagHistory]) { if self.histories != histories { self.histories = histories } } // sourcery:end + + public func update(followed: Bool, by mastodonUser: MastodonUser) { + if following { + if !self.followedBy.contains(mastodonUser) { + self.mutableSetValue(forKey: #keyPath(Tag.followedBy)).add(mastodonUser) + } + } else { + if self.followedBy.contains(mastodonUser) { + self.mutableSetValue(forKey: #keyPath(Tag.followedBy)).remove(mastodonUser) + } + } + } + } diff --git a/MastodonSDK/Sources/CoreDataStack/Entity/Transient/MastodonCardType.swift b/MastodonSDK/Sources/CoreDataStack/Entity/Transient/MastodonCardType.swift new file mode 100644 index 000000000..59401cf4a --- /dev/null +++ b/MastodonSDK/Sources/CoreDataStack/Entity/Transient/MastodonCardType.swift @@ -0,0 +1,34 @@ +// +// MastodonCardType.swift +// CoreDataStack +// +// Created by Kyle Bashour on 11/23/22. +// + +import Foundation + +public enum MastodonCardType: RawRepresentable, Equatable { + case link + case photo + case video + + case _other(String) + + public init(rawValue: String) { + switch rawValue { + case "link": self = .link + case "photo": self = .photo + case "video": self = .video + default: self = ._other(rawValue) + } + } + + public var rawValue: String { + switch self { + case .link: return "link" + case .photo: return "photo" + case .video: return "video" + case ._other(let value): return value + } + } +} diff --git a/MastodonSDK/Sources/CoreDataStack/Extension/NSManagedObjectContext.swift b/MastodonSDK/Sources/CoreDataStack/Extension/NSManagedObjectContext.swift index b921de819..3b4818992 100644 --- a/MastodonSDK/Sources/CoreDataStack/Extension/NSManagedObjectContext.swift +++ b/MastodonSDK/Sources/CoreDataStack/Extension/NSManagedObjectContext.swift @@ -50,43 +50,16 @@ extension NSManagedObjectContext { extension NSManagedObjectContext { public func perform(block: @escaping () throws -> T) async throws -> T { - if #available(iOS 15.0, *) { - return try await perform(schedule: .enqueued) { - try block() - } - } else { - return try await withCheckedThrowingContinuation { continuation in - self.perform { - do { - let value = try block() - continuation.resume(returning: value) - } catch { - continuation.resume(throwing: error) - } - } - } // end return + return try await perform(schedule: .enqueued) { + try block() } } - + public func performChanges(block: @escaping () throws -> T) async throws -> T { - if #available(iOS 15.0, *) { - return try await perform(schedule: .enqueued) { - let value = try block() - try self.saveOrRollback() - return value - } - } else { - return try await withCheckedThrowingContinuation { continuation in - self.perform { - do { - let value = try block() - try self.saveOrRollback() - continuation.resume(returning: value) - } catch { - continuation.resume(throwing: error) - } - } - } // end return + return try await perform(schedule: .enqueued) { + let value = try block() + try self.saveOrRollback() + return value } } // end func } diff --git a/MastodonSDK/Sources/CoreDataStack/Extension/UIFont.swift b/MastodonSDK/Sources/CoreDataStack/Extension/UIFont.swift index a1a97a112..97fb2f397 100644 --- a/MastodonSDK/Sources/CoreDataStack/Extension/UIFont.swift +++ b/MastodonSDK/Sources/CoreDataStack/Extension/UIFont.swift @@ -22,9 +22,9 @@ extension UIFont { let fontDescription = UIFontDescriptor.preferredFontDescriptor(withTextStyle: textStyle).addingAttributes([ UIFontDescriptor.AttributeName.featureSettings: [ [ - UIFontDescriptor.FeatureKey.featureIdentifier: + UIFontDescriptor.FeatureKey.type: kNumberSpacingType, - UIFontDescriptor.FeatureKey.typeIdentifier: + UIFontDescriptor.FeatureKey.selector: kMonospacedNumbersSelector ] ] diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.link.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Button/tagFollow.colorset/Contents.json similarity index 76% rename from MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.link.colorset/Contents.json rename to MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Button/tagFollow.colorset/Contents.json index f5112f04f..e7e41c6ff 100644 --- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.link.colorset/Contents.json +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Button/tagFollow.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.371", - "green" : "0.565", - "red" : "0.290" + "blue" : "0x38", + "green" : "0x29", + "red" : "0x2B" } }, "idiom" : "universal" @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.603", - "green" : "0.742", - "red" : "0.476" + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFF" } }, "idiom" : "universal" diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Button/tagUnfollow.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Button/tagUnfollow.colorset/Contents.json new file mode 100644 index 000000000..e7fbb60a6 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Button/tagUnfollow.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFF" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x38", + "green" : "0x29", + "red" : "0x2B" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.checkmark.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.text.colorset/Contents.json similarity index 100% rename from MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.checkmark.colorset/Contents.json rename to MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Profile/About/bio.about.field.verified.text.colorset/Contents.json diff --git a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift index 155227685..27914629d 100644 --- a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift +++ b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift @@ -49,6 +49,8 @@ public enum Asset { public static let actionToolbar = ColorAsset(name: "Colors/Button/action.toolbar") public static let disabled = ColorAsset(name: "Colors/Button/disabled") public static let inactive = ColorAsset(name: "Colors/Button/inactive") + public static let tagFollow = ColorAsset(name: "Colors/Button/tagFollow") + public static let tagUnfollow = ColorAsset(name: "Colors/Button/tagUnfollow") } public enum Icon { public static let plus = ColorAsset(name: "Colors/Icon/plus") @@ -173,8 +175,7 @@ public enum Asset { public enum Profile { public enum About { public static let bioAboutFieldVerifiedBackground = ColorAsset(name: "Scene/Profile/About/bio.about.field.verified.background") - public static let bioAboutFieldVerifiedCheckmark = ColorAsset(name: "Scene/Profile/About/bio.about.field.verified.checkmark") - public static let bioAboutFieldVerifiedLink = ColorAsset(name: "Scene/Profile/About/bio.about.field.verified.link") + public static let bioAboutFieldVerifiedText = ColorAsset(name: "Scene/Profile/About/bio.about.field.verified.text") } public enum Banner { public static let bioEditBackgroundGray = ColorAsset(name: "Scene/Profile/Banner/bio.edit.background.gray") diff --git a/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Instance.swift b/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Instance.swift index 4192b68a2..eebb16be4 100644 --- a/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Instance.swift +++ b/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Instance.swift @@ -23,3 +23,47 @@ extension Instance { return try? JSONEncoder().encode(configuration) } } + +extension Instance { + public var configurationV2: Mastodon.Entity.V2.Instance.Configuration? { + guard + let configurationRaw = configurationV2Raw, + let configuration = try? JSONDecoder().decode( + Mastodon.Entity.V2.Instance.Configuration.self, + from: configurationRaw + ) + else { + return nil + } + + return configuration + } + + static func encodeV2(configuration: Mastodon.Entity.V2.Instance.Configuration) -> Data? { + return try? JSONEncoder().encode(configuration) + } +} + +extension Instance { + public var canFollowTags: Bool { + version?.majorServerVersion(greaterThanOrEquals: 4) ?? false // following Tags is support beginning with Mastodon v4.0.0 + } + + var isTranslationEnabled: Bool { + if let configuration = configurationV2 { + return configuration.translation?.enabled == true + } + return false + } +} + +extension String { + public func majorServerVersion(greaterThanOrEquals comparedVersion: Int) -> Bool { + guard + let majorVersionString = split(separator: ".").first, + let majorVersionInt = Int(majorVersionString) + else { return false } + + return majorVersionInt >= comparedVersion + } +} diff --git a/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Status+Property.swift b/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Status+Property.swift index c4508a997..9e92e0d2c 100644 --- a/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Status+Property.swift +++ b/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Status+Property.swift @@ -51,14 +51,28 @@ extension Mastodon.Entity.Status { guard let mediaAttachments = mediaAttachments else { return [] } let attachments = mediaAttachments.compactMap { media -> MastodonAttachment? in - guard let kind = media.attachmentKind, - let meta = media.meta, - let original = meta.original, - let width = original.width, // audio has width/height - let height = original.height + guard let kind = media.attachmentKind else { return nil } - - let durationMS: Int? = original.duration.flatMap { Int($0 * 1000) } + + let width: Int; + let height: Int; + let durationMS: Int?; + + if let meta = media.meta, + let original = meta.original, + let originalWidth = original.width, + let originalHeight = original.height { + width = originalWidth // audio has width/height + height = originalHeight + durationMS = original.duration.map { Int($0 * 1000) } + } + else { + // In case metadata field is missing, use default values. + width = 32; + height = 32; + durationMS = nil; + } + return MastodonAttachment( id: media.id, kind: kind, diff --git a/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Tag+Property.swift b/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Tag+Property.swift index 633f7bddf..7411fd960 100644 --- a/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Tag+Property.swift +++ b/MastodonSDK/Sources/MastodonCore/Extension/CoreDataStack/Tag+Property.swift @@ -22,6 +22,7 @@ extension Tag.Property { updatedAt: networkDate, name: entity.name, url: entity.url, + following: entity.following ?? false, histories: { guard let histories = entity.history else { return [] } let result: [MastodonTagHistory] = histories.map { history in diff --git a/MastodonSDK/Sources/MastodonCore/Extension/NSItemProvider.swift b/MastodonSDK/Sources/MastodonCore/Extension/NSItemProvider.swift index c6fbff4f5..c5b8d513c 100644 --- a/MastodonSDK/Sources/MastodonCore/Extension/NSItemProvider.swift +++ b/MastodonSDK/Sources/MastodonCore/Extension/NSItemProvider.swift @@ -65,7 +65,7 @@ extension NSItemProvider { } let data = NSMutableData() - guard let imageDestination = CGImageDestinationCreateWithData(data, kUTTypeJPEG, 1, nil) else { + guard let imageDestination = CGImageDestinationCreateWithData(data, UTType.jpeg.identifier as CFString, 1, nil) else { continuation.resume(with: .success(nil)) assertionFailure() return diff --git a/MastodonSDK/Sources/MastodonCore/FetchedResultsController/FollowedTagsFetchedResultController.swift b/MastodonSDK/Sources/MastodonCore/FetchedResultsController/FollowedTagsFetchedResultController.swift new file mode 100644 index 000000000..8c5c64b58 --- /dev/null +++ b/MastodonSDK/Sources/MastodonCore/FetchedResultsController/FollowedTagsFetchedResultController.swift @@ -0,0 +1,77 @@ +// +// FollowedTagsFetchedResultController.swift +// +// +// Created by Marcus Kida on 23.11.22. +// + +import os.log +import UIKit +import Combine +import CoreData +import CoreDataStack +import MastodonSDK + +public final class FollowedTagsFetchedResultController: NSObject { + + var disposeBag = Set() + + let fetchedResultsController: NSFetchedResultsController + + // input + @Published public var domain: String? = nil + @Published public var user: MastodonUser? = nil + + // output + @Published public private(set) var records: [Tag] = [] + + public init(managedObjectContext: NSManagedObjectContext, domain: String, user: MastodonUser) { + self.domain = domain + self.fetchedResultsController = { + let fetchRequest = Tag.sortedFetchRequest + fetchRequest.predicate = Tag.predicate(domain: domain, following: true, by: user) + fetchRequest.sortDescriptors = Tag.defaultSortDescriptors + fetchRequest.returnsObjectsAsFaults = false + fetchRequest.fetchBatchSize = 20 + let controller = NSFetchedResultsController( + fetchRequest: fetchRequest, + managedObjectContext: managedObjectContext, + sectionNameKeyPath: nil, + cacheName: nil + ) + + return controller + }() + super.init() + + fetchedResultsController.delegate = self + try? fetchedResultsController.performFetch() + + Publishers.CombineLatest( + self.$domain, + self.$user + ) + .receive(on: DispatchQueue.main) + .sink { [weak self] domain, user in + guard let self = self, let domain = domain, let user = user else { return } + self.fetchedResultsController.fetchRequest.predicate = Tag.predicate(domain: domain, following: true, by: user) + do { + try self.fetchedResultsController.performFetch() + } catch { + assertionFailure(error.localizedDescription) + } + } + .store(in: &disposeBag) + } + +} + +// MARK: - NSFetchedResultsControllerDelegate +extension FollowedTagsFetchedResultController: NSFetchedResultsControllerDelegate { + public func controller(_ controller: NSFetchedResultsController, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) { + os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + + let objects = fetchedResultsController.fetchedObjects ?? [] + self.records = objects + } +} diff --git a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+Card.swift b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+Card.swift new file mode 100644 index 000000000..9ab8a817c --- /dev/null +++ b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+Card.swift @@ -0,0 +1,95 @@ +// +// Persistence+Card.swift +// +// +// Created by MainasuK on 2021-12-9. +// + +import CoreData +import CoreDataStack +import Foundation +import MastodonSDK +import os.log + +extension Persistence.Card { + + public struct PersistContext { + public let domain: String + public let entity: Mastodon.Entity.Card + public let me: MastodonUser? + public let log = Logger(subsystem: "Card", category: "Persistence") + public init( + domain: String, + entity: Mastodon.Entity.Card, + me: MastodonUser? + ) { + self.domain = domain + self.entity = entity + self.me = me + } + } + + public struct PersistResult { + public let card: Card + public let isNewInsertion: Bool + + public init( + card: Card, + isNewInsertion: Bool + ) { + self.card = card + self.isNewInsertion = isNewInsertion + } + + #if DEBUG + public let logger = Logger(subsystem: "Persistence.MastodonCard.PersistResult", category: "Persist") + public func log() { + let pollInsertionFlag = isNewInsertion ? "+" : "-" + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(pollInsertionFlag)](\(card.title)):") + } + #endif + } + + public static func create( + in managedObjectContext: NSManagedObjectContext, + context: PersistContext + ) -> PersistResult { + var type: MastodonCardType { + switch context.entity.type { + case .link: return .link + case .photo: return .photo + case .video: return .video + case .rich: return ._other(context.entity.type.rawValue) + case ._other(let rawValue): return ._other(rawValue) + } + } + + let property = Card.Property( + urlRaw: context.entity.url, + title: context.entity.title, + desc: context.entity.description, + type: type, + authorName: context.entity.authorName, + authorURLRaw: context.entity.authorURL, + providerName: context.entity.providerName, + providerURLRaw: context.entity.providerURL, + width: Int64(context.entity.width ?? 0), + height: Int64(context.entity.height ?? 0), + image: context.entity.image, + embedURLRaw: context.entity.embedURL, + blurhash: context.entity.blurhash, + html: context.entity.html.flatMap { $0.isEmpty ? nil : $0 } + ) + + let card = Card.insert( + into: managedObjectContext, + property: property + ) + + return PersistResult( + card: card, + isNewInsertion: true + ) + } + +} diff --git a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+Status.swift b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+Status.swift index a15e974e4..aa5eb8546 100644 --- a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+Status.swift +++ b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+Status.swift @@ -87,7 +87,7 @@ extension Persistence.Status { } if let oldStatus = fetch(in: managedObjectContext, context: context) { - merge(mastodonStatus: oldStatus, context: context) + merge(in: managedObjectContext, mastodonStatus: oldStatus, context: context) return PersistResult( status: oldStatus, isNewInsertion: false, @@ -107,7 +107,9 @@ extension Persistence.Status { ) return result.poll }() - + + let card = createCard(in: managedObjectContext, context: context) + let authorResult = Persistence.MastodonUser.createOrMerge( in: managedObjectContext, context: Persistence.MastodonUser.PersistContext( @@ -122,7 +124,8 @@ extension Persistence.Status { let relationship = Status.Relationship( author: author, reblog: reblog, - poll: poll + poll: poll, + card: card ) let status = create( in: managedObjectContext, @@ -182,6 +185,7 @@ extension Persistence.Status { } public static func merge( + in managedObjectContext: NSManagedObjectContext, mastodonStatus status: Status, context: PersistContext ) { @@ -203,8 +207,31 @@ extension Persistence.Status { ) ) } + + if status.card == nil, context.entity.card != nil { + let card = createCard(in: managedObjectContext, context: context) + let relationship = Card.Relationship(status: status) + card?.configure(relationship: relationship) + } + update(status: status, context: context) } + + private static func createCard( + in managedObjectContext: NSManagedObjectContext, + context: PersistContext + ) -> Card? { + guard let entity = context.entity.card else { return nil } + let result = Persistence.Card.create( + in: managedObjectContext, + context: Persistence.Card.PersistContext( + domain: context.domain, + entity: entity, + me: context.me + ) + ) + return result.card + } private static func update( status: Status, diff --git a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+Tag.swift b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+Tag.swift index 5c7130618..3071fed0d 100644 --- a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+Tag.swift +++ b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence+Tag.swift @@ -103,6 +103,9 @@ extension Persistence.Tag { property: property ) update(tag: object, context: context) + if let followingUser = context.me { + object.update(followed: property.following, by: followingUser) + } return object } @@ -116,7 +119,11 @@ extension Persistence.Tag { domain: context.domain, networkDate: context.networkDate ) + tag.update(property: property) + if let followingUser = context.me { + tag.update(followed: property.following, by: followingUser) + } update(tag: tag, context: context) } diff --git a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift index 350b603cc..3a36dec41 100644 --- a/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift +++ b/MastodonSDK/Sources/MastodonCore/Persistence/Persistence.swift @@ -15,6 +15,7 @@ extension Persistence { public enum MastodonUser { } public enum Status { } public enum Poll { } + public enum Card { } public enum PollOption { } public enum Tag { } public enum SearchHistory { } diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Account.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Account.swift index 1b6a57a83..8f89b4b76 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Account.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Account.swift @@ -161,3 +161,41 @@ extension APIService { } } + +extension APIService { + @discardableResult + public func getFollowedTags( + domain: String, + query: Mastodon.API.Account.FollowedTagsQuery, + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Tag]> { + let domain = authenticationBox.domain + let authorization = authenticationBox.userAuthorization + + let response = try await Mastodon.API.Account.followedTags( + session: session, + domain: domain, + query: query, + authorization: authorization + ).singleOutput() + + let managedObjectContext = self.backgroundManagedObjectContext + try await managedObjectContext.performChanges { + let me = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user + + for entity in response.value { + _ = Persistence.Tag.createOrMerge( + in: managedObjectContext, + context: Persistence.Tag.PersistContext( + domain: domain, + entity: entity, + me: me, + networkDate: response.networkDate + ) + ) + } + } + + return response + } // end func +} diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift index 7c78a65f7..19c5ff437 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Block.swift @@ -22,6 +22,45 @@ extension APIService { let isFollowing: Bool } + @discardableResult + public func getBlocked( + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Account]> { + try await _getBlocked(sinceID: nil, limit: nil, authenticationBox: authenticationBox) + } + + private func _getBlocked( + sinceID: Mastodon.Entity.Status.ID?, + limit: Int?, + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Account]> { + let managedObjectContext = backgroundManagedObjectContext + let response = try await Mastodon.API.Account.blocks( + session: session, + domain: authenticationBox.domain, + sinceID: sinceID, + limit: limit, + authorization: authenticationBox.userAuthorization + ).singleOutput() + + let userIDs = response.value.map { $0.id } + let predicate = MastodonUser.predicate(domain: authenticationBox.domain, ids: userIDs) + + let fetchRequest = MastodonUser.fetchRequest() + fetchRequest.predicate = predicate + fetchRequest.includesPropertyValues = false + + try await managedObjectContext.performChanges { + let users = try managedObjectContext.fetch(fetchRequest) as! [MastodonUser] + + for user in users { + user.deleteStatusAndNotificationFeeds(in: managedObjectContext) + } + } + + return response + } + public func toggleBlock( user: ManagedObjectRecord, authenticationBox: MastodonAuthenticationBox @@ -110,3 +149,21 @@ extension APIService { } } + +extension MastodonUser { + func deleteStatusAndNotificationFeeds(in context: NSManagedObjectContext) { + statuses.map { + $0.feeds + .union($0.reblogFrom.map { $0.feeds }.flatMap { $0 }) + .union($0.notifications.map { $0.feeds }.flatMap { $0 }) + } + .flatMap { $0 } + .forEach(context.delete) + + notifications.map { + $0.feeds + } + .flatMap { $0 } + .forEach(context.delete) + } +} diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Instance.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Instance.swift index 93bfcf09a..eb39b5585 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Instance.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Instance.swift @@ -20,4 +20,9 @@ extension APIService { return Mastodon.API.Instance.instance(session: session, domain: domain) } + public func instanceV2( + domain: String + ) -> AnyPublisher, Error> { + return Mastodon.API.V2.Instance.instance(session: session, domain: domain) + } } diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Mute.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Mute.swift index ee43ddce8..cc46872f4 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Mute.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Mute.swift @@ -21,6 +21,45 @@ extension APIService { let isMuting: Bool } + @discardableResult + public func getMutes( + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Account]> { + try await _getMutes(sinceID: nil, limit: nil, authenticationBox: authenticationBox) + } + + private func _getMutes( + sinceID: Mastodon.Entity.Status.ID?, + limit: Int?, + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Account]> { + let managedObjectContext = backgroundManagedObjectContext + let response = try await Mastodon.API.Account.mutes( + session: session, + domain: authenticationBox.domain, + sinceID: sinceID, + limit: limit, + authorization: authenticationBox.userAuthorization + ).singleOutput() + + let userIDs = response.value.map { $0.id } + let predicate = MastodonUser.predicate(domain: authenticationBox.domain, ids: userIDs) + + let fetchRequest = MastodonUser.fetchRequest() + fetchRequest.predicate = predicate + fetchRequest.includesPropertyValues = false + + try await managedObjectContext.performChanges { + let users = try managedObjectContext.fetch(fetchRequest) as! [MastodonUser] + + for user in users { + user.deleteStatusAndNotificationFeeds(in: managedObjectContext) + } + } + + return response + } + public func toggleMute( user: ManagedObjectRecord, authenticationBox: MastodonAuthenticationBox @@ -58,6 +97,7 @@ extension APIService { accountID: muteContext.targetUserID, authorization: authenticationBox.userAuthorization ).singleOutput() + try await getMutes(authenticationBox: authenticationBox) result = .success(response) } else { let response = try await Mastodon.API.Account.mute( @@ -66,6 +106,7 @@ extension APIService { accountID: muteContext.targetUserID, authorization: authenticationBox.userAuthorization ).singleOutput() + try await getMutes(authenticationBox: authenticationBox) result = .success(response) } } catch { diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Status+Translate.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Status+Translate.swift new file mode 100644 index 000000000..a802d6489 --- /dev/null +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Status+Translate.swift @@ -0,0 +1,34 @@ +// +// APIService+Status+Translate.swift +// Mastodon +// +// Created by Marcus Kida on 02.12.2022. +// + +import Foundation +import Combine +import CoreData +import CoreDataStack +import CommonOSLog +import MastodonSDK + +extension APIService { + + public func translateStatus( + statusID: Mastodon.Entity.Status.ID, + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content { + let domain = authenticationBox.domain + let authorization = authenticationBox.userAuthorization + + let response = try await Mastodon.API.Statuses.translate( + session: session, + domain: domain, + statusID: statusID, + authorization: authorization + ).singleOutput() + + return response + } + +} diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Tags.swift b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Tags.swift new file mode 100644 index 000000000..0b0320078 --- /dev/null +++ b/MastodonSDK/Sources/MastodonCore/Service/API/APIService+Tags.swift @@ -0,0 +1,92 @@ +// +// APIService+Tags.swift +// +// +// Created by Marcus Kida on 23.11.22. +// + +import os.log +import Foundation +import Combine +import CoreData +import CoreDataStack +import MastodonSDK + +extension APIService { + + public func getTagInformation( + for tag: String, + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content { + let domain = authenticationBox.domain + let authorization = authenticationBox.userAuthorization + + let response = try await Mastodon.API.Tags.getTagInformation( + session: session, + domain: domain, + tagId: tag, + authorization: authorization + ).singleOutput() + + return try await persistTag(from: response, domain: domain, authenticationBox: authenticationBox) + } // end func + + public func followTag( + for tag: String, + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content { + let domain = authenticationBox.domain + let authorization = authenticationBox.userAuthorization + + let response = try await Mastodon.API.Tags.followTag( + session: session, + domain: domain, + tagId: tag, + authorization: authorization + ).singleOutput() + + return try await persistTag(from: response, domain: domain, authenticationBox: authenticationBox) + } // end func + + public func unfollowTag( + for tag: String, + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content { + let domain = authenticationBox.domain + let authorization = authenticationBox.userAuthorization + + let response = try await Mastodon.API.Tags.unfollowTag( + session: session, + domain: domain, + tagId: tag, + authorization: authorization + ).singleOutput() + + return try await persistTag(from: response, domain: domain, authenticationBox: authenticationBox) + } // end func +} + +fileprivate extension APIService { + func persistTag( + from response: Mastodon.Response.Content, + domain: String, + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content { + let managedObjectContext = self.backgroundManagedObjectContext + try await managedObjectContext.performChanges { + let me = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user + + _ = Persistence.Tag.createOrMerge( + in: managedObjectContext, + context: Persistence.Tag.PersistContext( + domain: domain, + entity: response.value, + me: me, + networkDate: response.networkDate + ) + ) + } + + return response + } +} diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/CoreData/APIService+CoreData+Instance.swift b/MastodonSDK/Sources/MastodonCore/Service/API/CoreData/APIService+CoreData+Instance.swift index 2127a2981..d9566f6d4 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/API/CoreData/APIService+CoreData+Instance.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/API/CoreData/APIService+CoreData+Instance.swift @@ -46,7 +46,7 @@ extension APIService.CoreData { } else { let instance = Instance.insert( into: managedObjectContext, - property: Instance.Property(domain: domain) + property: Instance.Property(domain: domain, version: entity.version) ) let configurationRaw = entity.configuration.flatMap { Instance.encode(configuration: $0) } instance.update(configurationRaw: configurationRaw) @@ -69,7 +69,8 @@ extension APIService.CoreData { let configurationRaw = entity.configuration.flatMap { Instance.encode(configuration: $0) } instance.update(configurationRaw: configurationRaw) - + instance.version = entity.version + instance.didUpdate(at: networkDate) } diff --git a/MastodonSDK/Sources/MastodonCore/Service/API/CoreData/APIService+CoreData+InstanceV2.swift b/MastodonSDK/Sources/MastodonCore/Service/API/CoreData/APIService+CoreData+InstanceV2.swift new file mode 100644 index 000000000..19e188133 --- /dev/null +++ b/MastodonSDK/Sources/MastodonCore/Service/API/CoreData/APIService+CoreData+InstanceV2.swift @@ -0,0 +1,81 @@ +import os.log +import Foundation +import CoreData +import CoreDataStack +import MastodonSDK + +extension APIService.CoreData { + + public struct PersistContext { + public let domain: String + public let entity: Mastodon.Entity.V2.Instance + public let networkDate: Date + public let log: Logger + + public init( + domain: String, + entity: Mastodon.Entity.V2.Instance, + networkDate: Date, + log: Logger + ) { + self.domain = domain + self.entity = entity + self.networkDate = networkDate + self.log = log + } + } + + static func createOrMergeInstance( + in managedObjectContext: NSManagedObjectContext, + context: PersistContext + ) -> (instance: Instance, isCreated: Bool) { + // fetch old mastodon user + let old: Instance? = { + let request = Instance.sortedFetchRequest + request.predicate = Instance.predicate(domain: context.domain) + request.fetchLimit = 1 + request.returnsObjectsAsFaults = false + do { + return try managedObjectContext.fetch(request).first + } catch { + assertionFailure(error.localizedDescription) + return nil + } + }() + + if let old = old { + APIService.CoreData.merge( + instance: old, + context: context + ) + return (old, false) + } else { + let instance = Instance.insert( + into: managedObjectContext, + property: Instance.Property(domain: context.domain, version: context.entity.version) + ) + let configurationRaw = context.entity.configuration.flatMap { Instance.encodeV2(configuration: $0) } + instance.update(configurationV2Raw: configurationRaw) + + return (instance, true) + } + } + +} + +extension APIService.CoreData { + + static func merge( + instance: Instance, + context: PersistContext + ) { + guard context.networkDate > instance.updatedAt else { return } + + let configurationRaw = context.entity.configuration.flatMap { Instance.encodeV2(configuration: $0) } + instance.update(configurationV2Raw: configurationRaw) + instance.version = context.entity.version + + instance.didUpdate(at: context.networkDate) + } + +} diff --git a/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift b/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift index 4cd804036..0745e2f37 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/InstanceService.swift @@ -50,42 +50,18 @@ extension InstanceService { func updateInstance(domain: String) { guard let apiService = self.apiService else { return } apiService.instance(domain: domain) - .flatMap { response -> AnyPublisher, Error> in - let managedObjectContext = self.backgroundManagedObjectContext - return managedObjectContext.performChanges { - // get instance - let (instance, _) = APIService.CoreData.createOrMergeInstance( - into: managedObjectContext, - domain: domain, - entity: response.value, - networkDate: response.networkDate, - log: Logger(subsystem: "Update", category: "InstanceService") - ) - - // update relationship - let request = MastodonAuthentication.sortedFetchRequest - request.predicate = MastodonAuthentication.predicate(domain: domain) - request.returnsObjectsAsFaults = false - do { - let authentications = try managedObjectContext.fetch(request) - for authentication in authentications { - authentication.update(instance: instance) - } - } catch { - assertionFailure(error.localizedDescription) - } + .flatMap { [unowned self] response -> AnyPublisher in + if response.value.version?.majorServerVersion(greaterThanOrEquals: 4) == true { + return apiService.instanceV2(domain: domain) + .flatMap { return self.updateInstanceV2(domain: domain, response: $0) } + .eraseToAnyPublisher() + } else { + return self.updateInstance(domain: domain, response: response) } - .setFailureType(to: Error.self) - .tryMap { result -> Mastodon.Response.Content in - switch result { - case .success: - return response - case .failure(let error): - throw error - } - } - .eraseToAnyPublisher() } +// .flatMap { [unowned self] response -> AnyPublisher in +// return +// } .sink { [weak self] completion in guard let self = self else { return } switch completion { @@ -100,4 +76,102 @@ extension InstanceService { } .store(in: &disposeBag) } + + private func updateInstance(domain: String, response: Mastodon.Response.Content) -> AnyPublisher { + let managedObjectContext = self.backgroundManagedObjectContext + return managedObjectContext.performChanges { + // get instance + let (instance, _) = APIService.CoreData.createOrMergeInstance( + into: managedObjectContext, + domain: domain, + entity: response.value, + networkDate: response.networkDate, + log: Logger(subsystem: "Update", category: "InstanceService") + ) + + // update relationship + let request = MastodonAuthentication.sortedFetchRequest + request.predicate = MastodonAuthentication.predicate(domain: domain) + request.returnsObjectsAsFaults = false + do { + let authentications = try managedObjectContext.fetch(request) + for authentication in authentications { + authentication.update(instance: instance) + } + } catch { + assertionFailure(error.localizedDescription) + } + } + .setFailureType(to: Error.self) + .tryMap { result in + switch result { + case .success: + break + case .failure(let error): + throw error + } + } + .eraseToAnyPublisher() + } + + private func updateInstanceV2(domain: String, response: Mastodon.Response.Content) -> AnyPublisher { + let managedObjectContext = self.backgroundManagedObjectContext + return managedObjectContext.performChanges { + // get instance + let (instance, _) = APIService.CoreData.createOrMergeInstance( + in: managedObjectContext, + context: .init( + domain: domain, + entity: response.value, + networkDate: response.networkDate, + log: Logger(subsystem: "Update", category: "InstanceService") + ) + ) + + // update relationship + let request = MastodonAuthentication.sortedFetchRequest + request.predicate = MastodonAuthentication.predicate(domain: domain) + request.returnsObjectsAsFaults = false + do { + let authentications = try managedObjectContext.fetch(request) + for authentication in authentications { + authentication.update(instance: instance) + } + } catch { + assertionFailure(error.localizedDescription) + } + } + .setFailureType(to: Error.self) + .tryMap { result in + switch result { + case .success: + break + case .failure(let error): + throw error + } + } + .eraseToAnyPublisher() + } +} + +public extension InstanceService { + func updateMutesAndBlocks() { + Task { + for authBox in authenticationService?.mastodonAuthenticationBoxes ?? [] { + do { + try await apiService?.getMutes( + authenticationBox: authBox + ) + + try await apiService?.getBlocked( + authenticationBox: authBox + ) + + self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Instance] update mutes and blocks succeeded") + } catch { + self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Instance] update mutes and blocks failure: \(error.localizedDescription)") + } + } + } + } } diff --git a/MastodonSDK/Sources/MastodonCore/Service/Theme/ThemeService.swift b/MastodonSDK/Sources/MastodonCore/Service/Theme/ThemeService.swift index 869e6875f..446fb5b63 100644 --- a/MastodonSDK/Sources/MastodonCore/Service/Theme/ThemeService.swift +++ b/MastodonSDK/Sources/MastodonCore/Service/Theme/ThemeService.swift @@ -52,9 +52,7 @@ extension ThemeService { UINavigationBar.appearance().standardAppearance = appearance UINavigationBar.appearance().compactAppearance = appearance UINavigationBar.appearance().scrollEdgeAppearance = appearance - if #available(iOS 15.0, *) { - UINavigationBar.appearance().compactScrollEdgeAppearance = appearance - } + UINavigationBar.appearance().compactScrollEdgeAppearance = appearance // set tab bar appearance let tabBarAppearance = UITabBarAppearance() @@ -76,11 +74,7 @@ extension ThemeService { tabBarAppearance.backgroundColor = theme.tabBarBackgroundColor tabBarAppearance.selectionIndicatorTintColor = ThemeService.tintColor UITabBar.appearance().standardAppearance = tabBarAppearance - if #available(iOS 15.0, *) { - UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance - } else { - // Fallback on earlier versions - } + UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance UITabBar.appearance().barTintColor = theme.tabBarBackgroundColor // set table view cell appearance diff --git a/MastodonSDK/Sources/MastodonCore/Vendor/ItemProviderLoader.swift b/MastodonSDK/Sources/MastodonCore/Vendor/ItemProviderLoader.swift index 9899620fe..ad26e0ceb 100644 --- a/MastodonSDK/Sources/MastodonCore/Vendor/ItemProviderLoader.swift +++ b/MastodonSDK/Sources/MastodonCore/Vendor/ItemProviderLoader.swift @@ -48,13 +48,13 @@ extension ItemProviderLoader { let maxPixelSize: Int = 1536 // fit 120MB RAM limit #endif - let downsampleOptions = [ + let downsampleOptions: [CFString: Any] = [ kCGImageSourceCreateThumbnailFromImageAlways: true, kCGImageSourceCreateThumbnailWithTransform: true, kCGImageSourceThumbnailMaxPixelSize: maxPixelSize, - ] as CFDictionary + ] - guard let cgImage = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOptions) else { + guard let cgImage = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOptions as CFDictionary) else { // fallback to loadItem when create thumbnail failure itemProvider.loadItem(forTypeIdentifier: UTType.image.identifier, options: nil) { image, error in if let error = error { @@ -77,7 +77,7 @@ extension ItemProviderLoader { } let data = NSMutableData() - guard let imageDestination = CGImageDestinationCreateWithData(data, kUTTypeJPEG, 1, nil) else { + guard let imageDestination = CGImageDestinationCreateWithData(data, UTType.jpeg.identifier as CFString, 1, nil) else { promise(.success(nil)) return } diff --git a/MastodonSDK/Sources/MastodonExtension/Int.swift b/MastodonSDK/Sources/MastodonExtension/Int.swift new file mode 100644 index 000000000..e9c5ceb1e --- /dev/null +++ b/MastodonSDK/Sources/MastodonExtension/Int.swift @@ -0,0 +1,31 @@ +// +// Int.swift +// +// +// Created by Marcus Kida on 28.12.22. +// + +import Foundation + +public extension Int { + func asAbbreviatedCountString() -> String { + switch self { + case ..<1_000: + return String(format: "%d", locale: Locale.current, self) + case 1_000 ..< 999_999: + return String(format: "%.1fK", locale: Locale.current, Double(self) / 1_000) + .sanitizedAbbreviatedCountString(for: "K") + default: + return String(format: "%.1fM", locale: Locale.current, Double(self) / 1_000_000) + .sanitizedAbbreviatedCountString(for: "M") + } + } +} + +fileprivate extension String { + func sanitizedAbbreviatedCountString(for value: String) -> String { + [".0", ",0", "٫٠"].reduce(self) { res, acc in + return res.replacingOccurrences(of: "\(acc)\(value)", with: value) + } + } +} diff --git a/MastodonSDK/Sources/MastodonExtension/NSLayoutConstraint.swift b/MastodonSDK/Sources/MastodonExtension/NSLayoutConstraint.swift index 057b17859..3251eb58b 100644 --- a/MastodonSDK/Sources/MastodonExtension/NSLayoutConstraint.swift +++ b/MastodonSDK/Sources/MastodonExtension/NSLayoutConstraint.swift @@ -17,4 +17,16 @@ extension NSLayoutConstraint { self.identifier = identifier return self } + + @discardableResult + public func activate() -> Self { + self.isActive = true + return self + } + + @discardableResult + public func deactivate() -> Self { + self.isActive = false + return self + } } diff --git a/MastodonSDK/Sources/MastodonExtension/UIEdgeInsets.swift b/MastodonSDK/Sources/MastodonExtension/UIEdgeInsets.swift new file mode 100644 index 000000000..ea69bcefc --- /dev/null +++ b/MastodonSDK/Sources/MastodonExtension/UIEdgeInsets.swift @@ -0,0 +1,17 @@ +// +// UIEdgeInsets.swift +// +// +// Created by Jed Fox on 2022-11-24. +// + +import UIKit + +extension UIEdgeInsets { + public init(horizontal: CGFloat, vertical: CGFloat) { + self.init(top: vertical, left: horizontal, bottom: vertical, right: horizontal) + } + public static func constant(_ offset: CGFloat) -> Self { + UIEdgeInsets(top: offset, left: offset, bottom: offset, right: offset) + } +} diff --git a/MastodonSDK/Sources/MastodonExtension/UIView.swift b/MastodonSDK/Sources/MastodonExtension/UIView.swift index fa62be6c0..84f87eb20 100644 --- a/MastodonSDK/Sources/MastodonExtension/UIView.swift +++ b/MastodonSDK/Sources/MastodonExtension/UIView.swift @@ -48,18 +48,21 @@ extension UIView { } public extension UIView { - - func pinToParent() { - pinTo(to: self.superview) + @discardableResult + func pinToParent(padding: UIEdgeInsets = .zero) -> [NSLayoutConstraint] { + pinTo(to: self.superview, padding: padding) } - - func pinTo(to view: UIView?) { - guard let pinToView = view else { return } - NSLayoutConstraint.activate([ - topAnchor.constraint(equalTo: pinToView.topAnchor), - leadingAnchor.constraint(equalTo: pinToView.leadingAnchor), - trailingAnchor.constraint(equalTo: pinToView.trailingAnchor), - bottomAnchor.constraint(equalTo: pinToView.bottomAnchor), - ]) + + @discardableResult + func pinTo(to view: UIView?, padding: UIEdgeInsets = .zero) -> [NSLayoutConstraint] { + guard let pinToView = view else { return [] } + let constraints = [ + topAnchor.constraint(equalTo: pinToView.topAnchor, constant: padding.top), + leadingAnchor.constraint(equalTo: pinToView.leadingAnchor, constant: padding.left), + trailingAnchor.constraint(equalTo: pinToView.trailingAnchor, constant: -padding.right), + bottomAnchor.constraint(equalTo: pinToView.bottomAnchor, constant: -padding.bottom), + ] + NSLayoutConstraint.activate(constraints) + return constraints } } diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index 0392d2b05..b974ba7bc 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -87,6 +87,14 @@ public enum L10n { /// Sign Up Failure public static let title = L10n.tr("Localizable", "Common.Alerts.SignUpFailure.Title", fallback: "Sign Up Failure") } + public enum TranslationFailed { + /// OK + public static let button = L10n.tr("Localizable", "Common.Alerts.TranslationFailed.Button", fallback: "OK") + /// Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported. + public static let message = L10n.tr("Localizable", "Common.Alerts.TranslationFailed.Message", fallback: "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported.") + /// Note + public static let title = L10n.tr("Localizable", "Common.Alerts.TranslationFailed.Title", fallback: "Note") + } public enum VoteFailure { /// The poll has ended public static let pollEnded = L10n.tr("Localizable", "Common.Alerts.VoteFailure.PollEnded", fallback: "The poll has ended") @@ -112,6 +120,8 @@ public enum L10n { public static let confirm = L10n.tr("Localizable", "Common.Controls.Actions.Confirm", fallback: "Confirm") /// Continue public static let `continue` = L10n.tr("Localizable", "Common.Controls.Actions.Continue", fallback: "Continue") + /// Copy + public static let copy = L10n.tr("Localizable", "Common.Controls.Actions.Copy", fallback: "Copy") /// Copy Photo public static let copyPhoto = L10n.tr("Localizable", "Common.Controls.Actions.CopyPhoto", fallback: "Copy Photo") /// Delete @@ -178,6 +188,14 @@ public enum L10n { public static func unblockDomain(_ p1: Any) -> String { return L10n.tr("Localizable", "Common.Controls.Actions.UnblockDomain", String(describing: p1), fallback: "Unblock %@") } + public enum TranslatePost { + /// Translate from %@ + public static func title(_ p1: Any) -> String { + return L10n.tr("Localizable", "Common.Controls.Actions.TranslatePost.Title", String(describing: p1), fallback: "Translate from %@") + } + /// Unknown + public static let unknownLanguage = L10n.tr("Localizable", "Common.Controls.Actions.TranslatePost.UnknownLanguage", fallback: "Unknown") + } } public enum Friendship { /// Block @@ -272,6 +290,12 @@ public enum L10n { public enum Status { /// Content Warning public static let contentWarning = L10n.tr("Localizable", "Common.Controls.Status.ContentWarning", fallback: "Content Warning") + /// %@ via %@ + public static func linkViaUser(_ p1: Any, _ p2: Any) -> String { + return L10n.tr("Localizable", "Common.Controls.Status.LinkViaUser", String(describing: p1), String(describing: p2), fallback: "%@ via %@") + } + /// Load Embed + public static let loadEmbed = L10n.tr("Localizable", "Common.Controls.Status.LoadEmbed", fallback: "Load Embed") /// Tap anywhere to reveal public static let mediaContentWarning = L10n.tr("Localizable", "Common.Controls.Status.MediaContentWarning", fallback: "Tap anywhere to reveal") /// Sensitive Content @@ -301,6 +325,8 @@ public enum L10n { public static let reblog = L10n.tr("Localizable", "Common.Controls.Status.Actions.Reblog", fallback: "Reblog") /// Reply public static let reply = L10n.tr("Localizable", "Common.Controls.Status.Actions.Reply", fallback: "Reply") + /// Share Link in Post + public static let shareLinkInPost = L10n.tr("Localizable", "Common.Controls.Status.Actions.ShareLinkInPost", fallback: "Share Link in Post") /// Show GIF public static let showGif = L10n.tr("Localizable", "Common.Controls.Status.Actions.ShowGif", fallback: "Show GIF") /// Show image @@ -314,6 +340,18 @@ public enum L10n { /// Undo reblog public static let unreblog = L10n.tr("Localizable", "Common.Controls.Status.Actions.Unreblog", fallback: "Undo reblog") } + public enum Media { + /// %@, attachment %d of %d + public static func accessibilityLabel(_ p1: Any, _ p2: Int, _ p3: Int) -> String { + return L10n.tr("Localizable", "Common.Controls.Status.Media.AccessibilityLabel", String(describing: p1), p2, p3, fallback: "%@, attachment %d of %d") + } + /// Expands the GIF. Double-tap and hold to show actions + public static let expandGifHint = L10n.tr("Localizable", "Common.Controls.Status.Media.ExpandGifHint", fallback: "Expands the GIF. Double-tap and hold to show actions") + /// Expands the image. Double-tap and hold to show actions + public static let expandImageHint = L10n.tr("Localizable", "Common.Controls.Status.Media.ExpandImageHint", fallback: "Expands the image. Double-tap and hold to show actions") + /// Shows the video player. Double-tap and hold to show actions + public static let expandVideoHint = L10n.tr("Localizable", "Common.Controls.Status.Media.ExpandVideoHint", fallback: "Shows the video player. Double-tap and hold to show actions") + } public enum MetaEntity { /// Email address: %@ public static func email(_ p1: Any) -> String { @@ -352,6 +390,18 @@ public enum L10n { /// URL public static let url = L10n.tr("Localizable", "Common.Controls.Status.Tag.Url", fallback: "URL") } + public enum Translation { + /// Shown Original + public static let showOriginal = L10n.tr("Localizable", "Common.Controls.Status.Translation.ShowOriginal", fallback: "Shown Original") + /// Translated from %@ using %@ + public static func translatedFrom(_ p1: Any, _ p2: Any) -> String { + return L10n.tr("Localizable", "Common.Controls.Status.Translation.TranslatedFrom", String(describing: p1), String(describing: p2), fallback: "Translated from %@ using %@") + } + /// Unknown + public static let unknownLanguage = L10n.tr("Localizable", "Common.Controls.Status.Translation.UnknownLanguage", fallback: "Unknown") + /// Unknown + public static let unknownProvider = L10n.tr("Localizable", "Common.Controls.Status.Translation.UnknownProvider", fallback: "Unknown") + } public enum Visibility { /// Only mentioned user can see this post. public static let direct = L10n.tr("Localizable", "Common.Controls.Status.Visibility.Direct", fallback: "Only mentioned user can see this post.") @@ -370,8 +420,8 @@ public enum L10n { public static let notifications = L10n.tr("Localizable", "Common.Controls.Tabs.Notifications", fallback: "Notifications") /// Profile public static let profile = L10n.tr("Localizable", "Common.Controls.Tabs.Profile", fallback: "Profile") - /// Search - public static let search = L10n.tr("Localizable", "Common.Controls.Tabs.Search", fallback: "Search") + /// Search and Explore + public static let searchAndExplore = L10n.tr("Localizable", "Common.Controls.Tabs.SearchAndExplore", fallback: "Search and Explore") } public enum Timeline { /// Filtered @@ -633,6 +683,24 @@ public enum L10n { /// Favorited By public static let title = L10n.tr("Localizable", "Scene.FavoritedBy.Title", fallback: "Favorited By") } + public enum FollowedTags { + /// Followed Tags + public static let title = L10n.tr("Localizable", "Scene.FollowedTags.Title", fallback: "Followed Tags") + public enum Actions { + /// Follow + public static let follow = L10n.tr("Localizable", "Scene.FollowedTags.Actions.Follow", fallback: "Follow") + /// Unfollow + public static let unfollow = L10n.tr("Localizable", "Scene.FollowedTags.Actions.Unfollow", fallback: "Unfollow") + } + public enum Header { + /// participants + public static let participants = L10n.tr("Localizable", "Scene.FollowedTags.Header.Participants", fallback: "participants") + /// posts + public static let posts = L10n.tr("Localizable", "Scene.FollowedTags.Header.Posts", fallback: "posts") + /// posts today + public static let postsToday = L10n.tr("Localizable", "Scene.FollowedTags.Header.PostsToday", fallback: "posts today") + } + } public enum Follower { /// Followers from other servers are not displayed. public static let footer = L10n.tr("Localizable", "Scene.Follower.Footer", fallback: "Followers from other servers are not displayed.") @@ -660,8 +728,8 @@ public enum L10n { public enum Accessibility { /// Tap to scroll to top and tap again to previous location public static let logoHint = L10n.tr("Localizable", "Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint", fallback: "Tap to scroll to top and tap again to previous location") - /// Logo Button - public static let logoLabel = L10n.tr("Localizable", "Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel", fallback: "Logo Button") + /// Mastodon + public static let logoLabel = L10n.tr("Localizable", "Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel", fallback: "Mastodon") } } } @@ -736,15 +804,23 @@ public enum L10n { } public enum Dashboard { /// followers - public static let followers = L10n.tr("Localizable", "Scene.Profile.Dashboard.Followers", fallback: "followers") + public static let myFollowers = L10n.tr("Localizable", "Scene.Profile.Dashboard.MyFollowers", fallback: "followers") /// following - public static let following = L10n.tr("Localizable", "Scene.Profile.Dashboard.Following", fallback: "following") + public static let myFollowing = L10n.tr("Localizable", "Scene.Profile.Dashboard.MyFollowing", fallback: "following") /// posts - public static let posts = L10n.tr("Localizable", "Scene.Profile.Dashboard.Posts", fallback: "posts") + public static let myPosts = L10n.tr("Localizable", "Scene.Profile.Dashboard.MyPosts", fallback: "posts") + /// followers + public static let otherFollowers = L10n.tr("Localizable", "Scene.Profile.Dashboard.OtherFollowers", fallback: "followers") + /// following + public static let otherFollowing = L10n.tr("Localizable", "Scene.Profile.Dashboard.OtherFollowing", fallback: "following") + /// posts + public static let otherPosts = L10n.tr("Localizable", "Scene.Profile.Dashboard.OtherPosts", fallback: "posts") } public enum Fields { /// Add Row public static let addRow = L10n.tr("Localizable", "Scene.Profile.Fields.AddRow", fallback: "Add Row") + /// Joined + public static let joined = L10n.tr("Localizable", "Scene.Profile.Fields.Joined", fallback: "Joined") public enum Placeholder { /// Content public static let content = L10n.tr("Localizable", "Scene.Profile.Fields.Placeholder.Content", fallback: "Content") @@ -1320,9 +1396,9 @@ public enum L10n { public enum A11y { public enum Plural { public enum Count { - /// Plural format key: "%#@character_count@ left" + /// Plural format key: "%#@character_count@" public static func charactersLeft(_ p1: Int) -> String { - return L10n.tr("Localizable", "a11y.plural.count.characters_left", p1, fallback: "Plural format key: \"%#@character_count@ left\"") + return L10n.tr("Localizable", "a11y.plural.count.characters_left", p1, fallback: "Plural format key: \"%#@character_count@\"") } /// Plural format key: "Input limit exceeds %#@character_count@" public static func inputLimitExceeds(_ p1: Int) -> String { diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings index adeaad07b..fb3e483cf 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings @@ -22,6 +22,9 @@ Please check your internet connection."; "Common.Alerts.SignOut.Message" = "Are you sure you want to sign out?"; "Common.Alerts.SignOut.Title" = "Sign Out"; "Common.Alerts.SignUpFailure.Title" = "Sign Up Failure"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "The poll has ended"; "Common.Alerts.VoteFailure.Title" = "Vote Failure"; "Common.Controls.Actions.Add" = "Add"; @@ -31,6 +34,7 @@ Please check your internet connection."; "Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "Confirm"; "Common.Controls.Actions.Continue" = "Continue"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "Copy Photo"; "Common.Controls.Actions.Delete" = "Delete"; "Common.Controls.Actions.Discard" = "Discard"; @@ -59,6 +63,8 @@ Please check your internet connection."; "Common.Controls.Actions.SignUp" = "Create account"; "Common.Controls.Actions.Skip" = "Skip"; "Common.Controls.Actions.TakePhoto" = "Take Photo"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "Try Again"; "Common.Controls.Actions.UnblockDomain" = "Unblock %@"; "Common.Controls.Friendship.Block" = "Block"; @@ -100,6 +106,7 @@ 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.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "Show GIF"; "Common.Controls.Status.Actions.ShowImage" = "Show image"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; @@ -107,6 +114,12 @@ Please check your internet connection."; "Common.Controls.Status.Actions.Unfavorite" = "Unfavorite"; "Common.Controls.Status.Actions.Unreblog" = "Undo reblog"; "Common.Controls.Status.ContentWarning" = "Content Warning"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; +"Common.Controls.Status.Media.AccessibilityLabel" = "%@, attachment %d of %d"; +"Common.Controls.Status.Media.ExpandGifHint" = "Expands the GIF. Double-tap and hold to show actions"; +"Common.Controls.Status.Media.ExpandImageHint" = "Expands the image. Double-tap and hold to show actions"; +"Common.Controls.Status.Media.ExpandVideoHint" = "Shows the video player. Double-tap and hold to show actions"; "Common.Controls.Status.MediaContentWarning" = "Tap anywhere to reveal"; "Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; @@ -124,6 +137,10 @@ Please check your internet connection."; "Common.Controls.Status.Tag.Mention" = "Mention"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ reblogged"; "Common.Controls.Status.UserRepliedTo" = "Replied to %@"; "Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; @@ -133,7 +150,7 @@ Please check your internet connection."; "Common.Controls.Tabs.Home" = "Home"; "Common.Controls.Tabs.Notifications" = "Notifications"; "Common.Controls.Tabs.Profile" = "Profile"; -"Common.Controls.Tabs.Search" = "Search"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "Common.Controls.Timeline.Filtered" = "Filtered"; "Common.Controls.Timeline.Header.BlockedWarning" = "You can’t view this user’s profile until they unblock you."; @@ -229,12 +246,18 @@ uploaded to Mastodon."; "Scene.Familiarfollowers.Title" = "Followers you familiar"; "Scene.Favorite.Title" = "Your Favorites"; "Scene.FavoritedBy.Title" = "Favorited By"; +"Scene.FollowedTags.Actions.Follow" = "Follow"; +"Scene.FollowedTags.Actions.Unfollow" = "Unfollow"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "posts"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Followed Tags"; "Scene.Follower.Footer" = "Followers from other servers are not displayed."; "Scene.Follower.Title" = "follower"; "Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.Following.Title" = "following"; "Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; -"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Mastodon"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "See new posts"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; "Scene.HomeTimeline.NavigationBarState.Published" = "Published!"; @@ -264,10 +287,14 @@ uploaded to Mastodon."; "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"; +"Scene.Profile.Dashboard.MyFollowers" = "followers"; +"Scene.Profile.Dashboard.MyFollowing" = "following"; +"Scene.Profile.Dashboard.MyPosts" = "posts"; +"Scene.Profile.Dashboard.OtherFollowers" = "followers"; +"Scene.Profile.Dashboard.OtherFollowing" = "following"; +"Scene.Profile.Dashboard.OtherPosts" = "posts"; "Scene.Profile.Fields.AddRow" = "Add Row"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "Content"; "Scene.Profile.Fields.Placeholder.Label" = "Label"; "Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.stringsdict index f8964ca5d..37ce1f032 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.stringsdict @@ -71,7 +71,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -79,15 +79,15 @@ NSStringFormatValueTypeKey ld zero - no characters + no characters left one - 1 character + 1 character left few - %ld characters + %ld characters left many - %ld characters + %ld characters left other - %ld characters + %ld characters left plural.count.followed_by_and_mutual diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings index 17d0569c7..8ecefd32e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings @@ -22,6 +22,9 @@ "Common.Alerts.SignOut.Message" = "هل أنت متأكد من رغبتك في تسجيل الخُروج؟"; "Common.Alerts.SignOut.Title" = "تَسجيلُ الخُروج"; "Common.Alerts.SignUpFailure.Title" = "إخفاقٌ فِي التَّسجيل"; +"Common.Alerts.TranslationFailed.Button" = "حسنًا"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "مُلاحظة"; "Common.Alerts.VoteFailure.PollEnded" = "اِنتَهَى اِستِطلاعُ الرَّأي"; "Common.Alerts.VoteFailure.Title" = "إخفاقٌ فِي التَّصويت"; "Common.Controls.Actions.Add" = "إضافة"; @@ -31,6 +34,7 @@ "Common.Controls.Actions.Compose" = "تأليف"; "Common.Controls.Actions.Confirm" = "تأكيد"; "Common.Controls.Actions.Continue" = "واصل"; +"Common.Controls.Actions.Copy" = "نَسخ"; "Common.Controls.Actions.CopyPhoto" = "نسخ الصورة"; "Common.Controls.Actions.Delete" = "حذف"; "Common.Controls.Actions.Discard" = "تجاهُل"; @@ -56,9 +60,11 @@ "Common.Controls.Actions.SharePost" = "مشارك المنشور"; "Common.Controls.Actions.ShareUser" = "مُشارَكَةُ %@"; "Common.Controls.Actions.SignIn" = "تسجيلُ الدخول"; -"Common.Controls.Actions.SignUp" = "Create account"; +"Common.Controls.Actions.SignUp" = "إنشاءُ حِساب"; "Common.Controls.Actions.Skip" = "تخطي"; "Common.Controls.Actions.TakePhoto" = "اِلتِقاطُ صُورَة"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "المُحاولة مرة أُخرى"; "Common.Controls.Actions.UnblockDomain" = "رفع الحظر عن %@"; "Common.Controls.Friendship.Block" = "حظر"; @@ -100,6 +106,7 @@ "Common.Controls.Status.Actions.Menu" = "القائمة"; "Common.Controls.Status.Actions.Reblog" = "إعادة النشر"; "Common.Controls.Status.Actions.Reply" = "الرَّد"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "أظْهِر GIF"; "Common.Controls.Status.Actions.ShowImage" = "أظْهِرِ الصُّورَة"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "أظْهِر مُشَغِّلَ المَقاطِعِ المَرئِيَّة"; @@ -107,6 +114,8 @@ "Common.Controls.Status.Actions.Unfavorite" = "إزالة التفضيل"; "Common.Controls.Status.Actions.Unreblog" = "التراجُع عن إعادة النشر"; "Common.Controls.Status.ContentWarning" = "تحذير المُحتوى"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "اُنقُر لِلكَشف"; "Common.Controls.Status.MetaEntity.Email" = "عُنوان البريد الإلكتُروني: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "وَسْم: %@"; @@ -124,6 +133,10 @@ "Common.Controls.Status.Tag.Mention" = "إشارة"; "Common.Controls.Status.Tag.Url" = "عنوان URL"; "Common.Controls.Status.TapToReveal" = "اُنقُر لِلكَشف"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "أعادَ %@ تَدوينَها"; "Common.Controls.Status.UserRepliedTo" = "رَدًا على %@"; "Common.Controls.Status.Visibility.Direct" = "المُستخدمِونَ المُشارِ إليهم فَقَطْ مَن يُمكِنُهُم رُؤيَةُ هَذَا المَنشُور."; @@ -131,9 +144,9 @@ "Common.Controls.Status.Visibility.PrivateFromMe" = "فَقَطْ مُتابِعيني أنَا مَن يُمكِنُهُم رُؤيَةُ هَذَا المَنشُور."; "Common.Controls.Status.Visibility.Unlisted" = "يُمكِنُ لِلجَميعِ رُؤيَةُ هَذَا المَنشورِ وَلكِنَّهُ لَا يُعرَضُ فِي الخَطِّ الزَمنيّ العام."; "Common.Controls.Tabs.Home" = "الرَّئِيسَة"; -"Common.Controls.Tabs.Notification" = "الإشعارات"; +"Common.Controls.Tabs.Notifications" = "الإشعارات"; "Common.Controls.Tabs.Profile" = "المِلَفُّ التَّعريفِيّ"; -"Common.Controls.Tabs.Search" = "البَحث"; +"Common.Controls.Tabs.SearchAndExplore" = "البَحث وَالاِستِكشاف"; "Common.Controls.Timeline.Filtered" = "مُصفَّى"; "Common.Controls.Timeline.Header.BlockedWarning" = "لا يُمكِنُكَ عَرض الملف التَعريفي لهذا المُستخدِم حتَّى يَرفَعَ الحَظرَ عَنك."; @@ -161,7 +174,7 @@ "Scene.Compose.Accessibility.CustomEmojiPicker" = "منتقي الرموز التعبيرية المُخصَّص"; "Scene.Compose.Accessibility.DisableContentWarning" = "تعطيل تحذير المُحتَوى"; "Scene.Compose.Accessibility.EnableContentWarning" = "تفعيل تحذير المُحتَوى"; -"Scene.Compose.Accessibility.PostOptions" = "Post Options"; +"Scene.Compose.Accessibility.PostOptions" = "خياراتُ المَنشور"; "Scene.Compose.Accessibility.PostVisibilityMenu" = "قائمة ظهور المنشور"; "Scene.Compose.Accessibility.PostingAs" = "نَشر كَـ %@"; "Scene.Compose.Accessibility.RemovePoll" = "إزالة الاستطلاع"; @@ -229,6 +242,12 @@ "Scene.Familiarfollowers.Title" = "مُتابِعُونَ مَألُوفُونَ بِالنِّسبَةِ لَك"; "Scene.Favorite.Title" = "مُفضَّلَتُك"; "Scene.FavoritedBy.Title" = "مُفَضَّلٌ مِن قِبَلِ"; +"Scene.FollowedTags.Actions.Follow" = "مُتابَعَة"; +"Scene.FollowedTags.Actions.Unfollow" = "إلغاءُ المُتابَعَة"; +"Scene.FollowedTags.Header.Participants" = "المُشارِكُون"; +"Scene.FollowedTags.Header.Posts" = "مَنشورات"; +"Scene.FollowedTags.Header.PostsToday" = "مَنشوراتُ اليَوم"; +"Scene.FollowedTags.Title" = "وُسُومُ المُتابَع"; "Scene.Follower.Footer" = "لا يُمكِن عَرض المُتابِعين مِنَ الخوادم الأُخرى."; "Scene.Follower.Title" = "مُتابِعِين"; "Scene.Following.Footer" = "لا يُمكِن عَرض المُتابَعات مِنَ الخوادم الأُخرى."; @@ -240,9 +259,9 @@ "Scene.HomeTimeline.NavigationBarState.Published" = "تمَّ النَّشر!"; "Scene.HomeTimeline.NavigationBarState.Publishing" = "يَجري نَشر المُشارَكَة..."; "Scene.HomeTimeline.Title" = "الرَّئِيسَة"; -"Scene.Login.ServerSearchField.Placeholder" = "Enter URL or search for your server"; -"Scene.Login.Subtitle" = "Log you in on the server you created your account on."; -"Scene.Login.Title" = "Welcome back"; +"Scene.Login.ServerSearchField.Placeholder" = "أدخِل عُنوانَ URL أو اِبحَث عَنِ الخادِمِ الخاصّ بِك"; +"Scene.Login.Subtitle" = "سَجِّل دُخولَكَ إلى الخادِم الَّذي أنشأتَ حِسابَكَ فيه."; +"Scene.Login.Title" = "مَرحَبًا بِكَ مُجَدَّدًا"; "Scene.Notification.FollowRequest.Accept" = "قَبُول"; "Scene.Notification.FollowRequest.Accepted" = "مَقبُول"; "Scene.Notification.FollowRequest.Reject" = "رَفض"; @@ -268,6 +287,7 @@ "Scene.Profile.Dashboard.Following" = "مُتابَع"; "Scene.Profile.Dashboard.Posts" = "مَنشورات"; "Scene.Profile.Fields.AddRow" = "إضافة صف"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "المُحتَوى"; "Scene.Profile.Fields.Placeholder.Label" = "التسمية"; "Scene.Profile.Fields.Verified.Long" = "تمَّ التَّحقق مِن مِلكية هذا الرابِطِ بِتاريخ %@"; @@ -404,11 +424,11 @@ "Scene.ServerPicker.EmptyState.BadNetwork" = "حدث خطأٌ ما أثناء تحميل البيانات. تحقَّق من اتصالك بالإنترنت."; "Scene.ServerPicker.EmptyState.FindingServers" = "يجري إيجاد خوادم متوفِّرَة..."; "Scene.ServerPicker.EmptyState.NoResults" = "لا توجد نتائج"; -"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "اِبحث عَن مُجتَمَعَات أو أدخِل عُنوانَ URL"; "Scene.ServerPicker.Label.Category" = "الفئة"; "Scene.ServerPicker.Label.Language" = "اللُّغَة"; "Scene.ServerPicker.Label.Users" = "مُستَخدِم"; -"Scene.ServerPicker.Subtitle" = "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers."; +"Scene.ServerPicker.Subtitle" = "اِختر خادمًا بناءً على منطقتك، اِهتماماتك أو يُمكنك حتى اِختيارُ مجتمعٍ ذِي غرضٍ عام. بِإمكانِكَ الدردشة مع أي شخص على مَاستودُون، بغض النظر عن الخادم الخاصة بك."; "Scene.ServerPicker.Title" = "اِختر خادِم، أيًّا مِنهُم."; "Scene.ServerRules.Button.Confirm" = "أنا مُوافِق"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict index 91368a4fb..35727c0d6 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict @@ -77,7 +77,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + يتبقى %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -91,9 +91,9 @@ two حَرفانِ اِثنان few - %ld characters + %ld أحرُف many - %ld characters + %ld حَرفًا other %ld حَرف diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings index 43c63deda..acd53cc03 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings @@ -1,36 +1,40 @@ -"Common.Alerts.BlockDomain.BlockEntireDomain" = "Bloquejar Domini"; -"Common.Alerts.BlockDomain.Title" = "Estàs segur, realment segur que vols bloquejar totalment %@? En la majoria dels casos bloquejar o silenciar uns pocs objectius és suficient i preferible. No veureu contingut d’aquest domini i se suprimirà qualsevol dels vostres seguidors d’aquest domini."; +"Common.Alerts.BlockDomain.BlockEntireDomain" = "Bloca el domini"; +"Common.Alerts.BlockDomain.Title" = "Estàs totalment segur que vols bloquejar per complet %@? En la majoria dels casos bloquejar o silenciar uns pocs objectius és suficient i preferible. No veureu contingut d’aquest domini i se suprimirà qualsevol dels vostres seguidors d’aquest domini."; "Common.Alerts.CleanCache.Message" = "S'ha netejat correctament la memòria cau de %@."; "Common.Alerts.CleanCache.Title" = "Neteja la memòria cau"; -"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" = "Esborrar Publicació"; -"Common.Alerts.DiscardPostContent.Message" = "Confirma per a descartar el contingut de la publicació composta."; +"Common.Alerts.Common.PleaseTryAgain" = "Torna-ho a provar."; +"Common.Alerts.Common.PleaseTryAgainLater" = "Prova-ho més tard."; +"Common.Alerts.DeletePost.Message" = "Segur que vols eliminar aquesta publicació?"; +"Common.Alerts.DeletePost.Title" = "Eliminar la publicació"; +"Common.Alerts.DiscardPostContent.Message" = "Confirma per a descartar el contingut de la publicació."; "Common.Alerts.DiscardPostContent.Title" = "Descarta l'esborrany"; -"Common.Alerts.EditProfileFailure.Message" = "No es pot editar el perfil. Si us plau torna-ho a provar."; -"Common.Alerts.EditProfileFailure.Title" = "Error al Editar el Perfil"; -"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "No pots adjuntar més d'un vídeo."; +"Common.Alerts.EditProfileFailure.Message" = "No es pot editar el perfil. Torna-ho a provar."; +"Common.Alerts.EditProfileFailure.Title" = "Error en editar el perfil"; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "No es pot adjuntar més d'un vídeo."; "Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "No es pot adjuntar un vídeo a una publicació que ja contingui imatges."; "Common.Alerts.PublishPostFailure.Message" = "No s'ha pogut enviar la publicació. -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" = "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ó?"; -"Common.Alerts.SignOut.Title" = "Tancar Sessió"; +Comprova la connexió a Internet."; +"Common.Alerts.PublishPostFailure.Title" = "Error en publicar"; +"Common.Alerts.SavePhotoFailure.Message" = "Activa el permís d'accés a la biblioteca de fotos per a desar-la."; +"Common.Alerts.SavePhotoFailure.Title" = "Error en desar la foto"; +"Common.Alerts.ServerError.Title" = "Error del servidor"; +"Common.Alerts.SignOut.Confirm" = "Tanca la sessió"; +"Common.Alerts.SignOut.Message" = "Segur que vols tancar la sessió?"; +"Common.Alerts.SignOut.Title" = "Tanca la sessió"; "Common.Alerts.SignUpFailure.Title" = "Error en el registre"; +"Common.Alerts.TranslationFailed.Button" = "D'acord"; +"Common.Alerts.TranslationFailed.Message" = "La traducció ha fallat. Potser l'administrador d'aquest servidor no ha activat les traduccions o està executant una versió vella de Mastodon on les traduccions encara no eren suportades."; +"Common.Alerts.TranslationFailed.Title" = "Nota"; "Common.Alerts.VoteFailure.PollEnded" = "L'enquesta ha finalitzat"; -"Common.Alerts.VoteFailure.Title" = "Error del Vot"; +"Common.Alerts.VoteFailure.Title" = "Error en votar"; "Common.Controls.Actions.Add" = "Afegeix"; "Common.Controls.Actions.Back" = "Enrere"; "Common.Controls.Actions.BlockDomain" = "Bloqueja %@"; "Common.Controls.Actions.Cancel" = "Cancel·la"; -"Common.Controls.Actions.Compose" = "Composa"; +"Common.Controls.Actions.Compose" = "Redacta"; "Common.Controls.Actions.Confirm" = "Confirma"; "Common.Controls.Actions.Continue" = "Continua"; +"Common.Controls.Actions.Copy" = "Copia"; "Common.Controls.Actions.CopyPhoto" = "Copia la foto"; "Common.Controls.Actions.Delete" = "Suprimeix"; "Common.Controls.Actions.Discard" = "Descarta"; @@ -50,21 +54,23 @@ Comprova la teva connexió a Internet."; "Common.Controls.Actions.ReportUser" = "Informa sobre %@"; "Common.Controls.Actions.Save" = "Desa"; "Common.Controls.Actions.SavePhoto" = "Desa la foto"; -"Common.Controls.Actions.SeeMore" = "Veure més"; +"Common.Controls.Actions.SeeMore" = "Mostra'n més"; "Common.Controls.Actions.Settings" = "Configuració"; "Common.Controls.Actions.Share" = "Comparteix"; -"Common.Controls.Actions.SharePost" = "Compartir Publicació"; -"Common.Controls.Actions.ShareUser" = "Compartir %@"; -"Common.Controls.Actions.SignIn" = "Iniciar sessió"; +"Common.Controls.Actions.SharePost" = "Comparteix la publicació"; +"Common.Controls.Actions.ShareUser" = "Comparteix %@"; +"Common.Controls.Actions.SignIn" = "Inicia sessió"; "Common.Controls.Actions.SignUp" = "Crea un compte"; "Common.Controls.Actions.Skip" = "Omet"; "Common.Controls.Actions.TakePhoto" = "Fes una foto"; +"Common.Controls.Actions.TranslatePost.Title" = "Traduït del %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Desconegut"; "Common.Controls.Actions.TryAgain" = "Torna a provar"; "Common.Controls.Actions.UnblockDomain" = "Desbloqueja %@"; -"Common.Controls.Friendship.Block" = "Bloqueja"; -"Common.Controls.Friendship.BlockDomain" = "Bloqueja %@"; -"Common.Controls.Friendship.BlockUser" = "Bloqueja %@"; -"Common.Controls.Friendship.Blocked" = "Bloquejat"; +"Common.Controls.Friendship.Block" = "Bloca"; +"Common.Controls.Friendship.BlockDomain" = "Bloca %@"; +"Common.Controls.Friendship.BlockUser" = "Bloca %@"; +"Common.Controls.Friendship.Blocked" = "Blocat"; "Common.Controls.Friendship.EditInfo" = "Edita"; "Common.Controls.Friendship.Follow" = "Segueix"; "Common.Controls.Friendship.Following" = "Seguint"; @@ -73,10 +79,10 @@ Comprova la teva connexió a Internet."; "Common.Controls.Friendship.MuteUser" = "Silencia %@"; "Common.Controls.Friendship.Muted" = "Silenciat"; "Common.Controls.Friendship.Pending" = "Pendent"; -"Common.Controls.Friendship.Request" = "Petició"; +"Common.Controls.Friendship.Request" = "Sol·licitud"; "Common.Controls.Friendship.ShowReblogs" = "Mostra els impulsos"; -"Common.Controls.Friendship.Unblock" = "Desbloqueja"; -"Common.Controls.Friendship.UnblockUser" = "Desbloqueja %@"; +"Common.Controls.Friendship.Unblock" = "Desbloca"; +"Common.Controls.Friendship.UnblockUser" = "Desbloca %@"; "Common.Controls.Friendship.Unmute" = "Deixa de silenciar"; "Common.Controls.Friendship.UnmuteUser" = "Treure silenci de %@"; "Common.Controls.Keyboard.Common.ComposeNewPost" = "Redacta un nova publicació"; @@ -86,31 +92,34 @@ Comprova la teva connexió a Internet."; "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 de l'impuls"; "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.Status.Actions.Favorite" = "Favorit"; "Common.Controls.Status.Actions.Hide" = "Amaga"; "Common.Controls.Status.Actions.Menu" = "Menú"; -"Common.Controls.Status.Actions.Reblog" = "Impuls"; +"Common.Controls.Status.Actions.Reblog" = "Impulsa"; "Common.Controls.Status.Actions.Reply" = "Respon"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Compartir l'Enllaç en el Tut"; "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.Actions.Unfavorite" = "Desfés el favorit"; +"Common.Controls.Status.Actions.Unreblog" = "Desfés l'impuls"; "Common.Controls.Status.ContentWarning" = "Advertència de Contingut"; +"Common.Controls.Status.LinkViaUser" = "%@ través de %@"; +"Common.Controls.Status.LoadEmbed" = "Carregar incrustat"; "Common.Controls.Status.MediaContentWarning" = "Toca qualsevol lloc per a mostrar"; "Common.Controls.Status.MetaEntity.Email" = "Correu electrònic: %@"; -"Common.Controls.Status.MetaEntity.Hashtag" = "Etiqueta %@"; -"Common.Controls.Status.MetaEntity.Mention" = "Mostra el Perfil: %@"; +"Common.Controls.Status.MetaEntity.Hashtag" = "Etiqueta: %@"; +"Common.Controls.Status.MetaEntity.Mention" = "Mostra el perfil: %@"; "Common.Controls.Status.MetaEntity.Url" = "Enllaç: %@"; "Common.Controls.Status.Poll.Closed" = "Finalitzada"; "Common.Controls.Status.Poll.Vote" = "Vota"; @@ -118,38 +127,42 @@ Comprova la teva connexió a Internet."; "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"; +"Common.Controls.Status.Tag.Emoji" = "Emojis"; "Common.Controls.Status.Tag.Hashtag" = "Etiqueta"; "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.Translation.ShowOriginal" = "Mostra l'original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Desconegut"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "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ó."; "Common.Controls.Status.Visibility.Private" = "Només els seus seguidors poden veure aquesta publicació."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Només els meus seguidors poden veure aquesta publicació."; -"Common.Controls.Status.Visibility.Unlisted" = "Tothom pot veure aquesta publicació però no es mostra en la línia de temps pública."; +"Common.Controls.Status.Visibility.Unlisted" = "Tothom pot veure aquesta publicació, però no es mostra en la línia de temps pública."; "Common.Controls.Tabs.Home" = "Inici"; -"Common.Controls.Tabs.Notification" = "Notificació"; +"Common.Controls.Tabs.Notifications" = "Notificacions"; "Common.Controls.Tabs.Profile" = "Perfil"; -"Common.Controls.Tabs.Search" = "Cerca"; +"Common.Controls.Tabs.SearchAndExplore" = "Cerca i Explora"; "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 desbloqui."; "Common.Controls.Timeline.Header.BlockingWarning" = "No pots veure el perfil d'aquest usuari - fins que el desbloquegis. +fins que el desbloquis. El teu perfil els sembla així."; "Common.Controls.Timeline.Header.NoStatusFound" = "No s'ha trobat cap publicació"; "Common.Controls.Timeline.Header.SuspendedWarning" = "Aquest usuari ha estat suspès."; "Common.Controls.Timeline.Header.UserBlockedWarning" = "No pots veure el perfil de %@ - fins que et desbloquegi."; + fins que et desbloqui."; "Common.Controls.Timeline.Header.UserBlockingWarning" = "No pots veure el perfil de %@ - fins que el desbloquegis. +fins que el desbloquis. 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 faltants"; -"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Carregant les publicacions faltants..."; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Carrega les publicacions restants"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Carregant les publicacions restants..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Mostra més respostes"; "Common.Controls.Timeline.Timestamp.Now" = "Ara"; "Scene.AccountList.AddAccount" = "Afegir compte"; @@ -161,8 +174,8 @@ El teu perfil els sembla així."; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Selector d'Emoji Personalitzat"; "Scene.Compose.Accessibility.DisableContentWarning" = "Desactiva l'Avís de Contingut"; "Scene.Compose.Accessibility.EnableContentWarning" = "Activa l'Avís de Contingut"; -"Scene.Compose.Accessibility.PostOptions" = "Opcions del tut"; -"Scene.Compose.Accessibility.PostVisibilityMenu" = "Menú de Visibilitat de Publicació"; +"Scene.Compose.Accessibility.PostOptions" = "Opcions del Tut"; +"Scene.Compose.Accessibility.PostVisibilityMenu" = "Menú de Visibilitat del Tut"; "Scene.Compose.Accessibility.PostingAs" = "Publicant com a %@"; "Scene.Compose.Accessibility.RemovePoll" = "Eliminar Enquesta"; "Scene.Compose.Attachment.AttachmentBroken" = "Aquest %@ està trencat i no pot ser @@ -170,8 +183,8 @@ carregat a Mastodon."; "Scene.Compose.Attachment.AttachmentTooLarge" = "El fitxer adjunt és massa gran"; "Scene.Compose.Attachment.CanNotRecognizeThisMediaAttachment" = "No es pot reconèixer aquest adjunt multimèdia"; "Scene.Compose.Attachment.CompressingState" = "Comprimint..."; -"Scene.Compose.Attachment.DescriptionPhoto" = "Descriu la foto per als disminuïts visuals..."; -"Scene.Compose.Attachment.DescriptionVideo" = "Descriu el vídeo per als disminuïts visuals..."; +"Scene.Compose.Attachment.DescriptionPhoto" = "Descriu la foto per a les persones amb diversitat funcional..."; +"Scene.Compose.Attachment.DescriptionVideo" = "Descriu el vídeo per a les persones amb diversitat funcional..."; "Scene.Compose.Attachment.LoadFailed" = "Ha fallat la càrrega"; "Scene.Compose.Attachment.Photo" = "foto"; "Scene.Compose.Attachment.ServerProcessingState" = "Servidor processant..."; @@ -182,8 +195,8 @@ carregat a Mastodon."; "Scene.Compose.ContentInputPlaceholder" = "Escriu o enganxa el que tinguis en ment"; "Scene.Compose.ContentWarning.Placeholder" = "Escriu un advertiment precís aquí..."; "Scene.Compose.Keyboard.AppendAttachmentEntry" = "Afegeix Adjunt - %@"; -"Scene.Compose.Keyboard.DiscardPost" = "Descarta la Publicació"; -"Scene.Compose.Keyboard.PublishPost" = "Envia la Publicació"; +"Scene.Compose.Keyboard.DiscardPost" = "Descarta el Tut"; +"Scene.Compose.Keyboard.PublishPost" = "Envia el Tut"; "Scene.Compose.Keyboard.SelectVisibilityEntry" = "Selecciona la Visibilitat - %@"; "Scene.Compose.Keyboard.ToggleContentWarning" = "Commuta l'Avís de Contingut"; "Scene.Compose.Keyboard.TogglePoll" = "Commuta l'enquesta"; @@ -201,7 +214,7 @@ carregat a Mastodon."; "Scene.Compose.Poll.ThirtyMinutes" = "30 minuts"; "Scene.Compose.Poll.ThreeDays" = "3 Dies"; "Scene.Compose.ReplyingToUser" = "responent a %@"; -"Scene.Compose.Title.NewPost" = "Nova publicació"; +"Scene.Compose.Title.NewPost" = "Nou Tut"; "Scene.Compose.Title.NewReply" = "Nova Resposta"; "Scene.Compose.Visibility.Direct" = "Només les persones que menciono"; "Scene.Compose.Visibility.Private" = "Només seguidors"; @@ -219,16 +232,22 @@ carregat a Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Toca l'enllaç del correu electrònic que t'hem enviat per a confirmar el teu compte."; "Scene.ConfirmEmail.TapTheLinkWeEmailedToYouToVerifyYourAccount" = "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.Intro" = "Aquestes son les publicacions que criden l'atenció en el teu racó de Mastodon."; +"Scene.Discovery.Intro" = "Aquests son els tuts que criden l'atenció en el teu racó de Mastodon."; "Scene.Discovery.Tabs.Community" = "Comunitat"; "Scene.Discovery.Tabs.ForYou" = "Per a tu"; "Scene.Discovery.Tabs.Hashtags" = "Etiquetes"; "Scene.Discovery.Tabs.News" = "Notícies"; -"Scene.Discovery.Tabs.Posts" = "Publicacions"; +"Scene.Discovery.Tabs.Posts" = "Tuts"; "Scene.Familiarfollowers.FollowedByNames" = "Seguit per %@"; "Scene.Familiarfollowers.Title" = "Seguidors coneguts"; "Scene.Favorite.Title" = "Els teus Favorits"; "Scene.FavoritedBy.Title" = "Preferit per"; +"Scene.FollowedTags.Actions.Follow" = "Segueix"; +"Scene.FollowedTags.Actions.Unfollow" = "Deixa de seguir"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "tuts"; +"Scene.FollowedTags.Header.PostsToday" = "tuts d'avui"; +"Scene.FollowedTags.Title" = "Etiquetes seguides"; "Scene.Follower.Footer" = "Els seguidors d'altres servidors no son mostrats."; "Scene.Follower.Title" = "seguidor"; "Scene.Following.Footer" = "Els seguits d'altres servidors no son mostrats."; @@ -266,29 +285,30 @@ carregat a Mastodon."; "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"; +"Scene.Profile.Dashboard.Posts" = "tuts"; "Scene.Profile.Fields.AddRow" = "Afegeix fila"; +"Scene.Profile.Fields.Joined" = "S'hi va unir"; "Scene.Profile.Fields.Placeholder.Content" = "Contingut"; "Scene.Profile.Fields.Placeholder.Label" = "Etiqueta"; "Scene.Profile.Fields.Verified.Long" = "La propietat d'aquest enllaç es va verificar el dia %@"; "Scene.Profile.Fields.Verified.Short" = "Verificat a %@"; "Scene.Profile.Header.FollowsYou" = "Et segueix"; -"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Confirma per a bloquejar %@"; -"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Bloqueja el Compte"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Confirma per a blocar %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Bloca el Compte"; "Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Confirma per a amagar els impulsos"; "Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Amaga Impulsos"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Confirma per a silenciar %@"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Silencia el Compte"; "Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Confirma per a mostrar els impulsos"; "Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Mostra els Impulsos"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Confirma per a desbloquejar %@"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Desbloqueja el Compte"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Confirma per a desblocar %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Desbloca el Compte"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Confirma deixar de silenciar a %@"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Desfer silenciar compte"; "Scene.Profile.SegmentedControl.About" = "Quant a"; "Scene.Profile.SegmentedControl.Media" = "Mèdia"; -"Scene.Profile.SegmentedControl.Posts" = "Publicacions"; -"Scene.Profile.SegmentedControl.PostsAndReplies" = "Publicacions i Respostes"; +"Scene.Profile.SegmentedControl.Posts" = "Tuts"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "Tuts i Respostes"; "Scene.Profile.SegmentedControl.Replies" = "Respostes"; "Scene.RebloggedBy.Title" = "Impulsat per"; "Scene.Register.Error.Item.Agreement" = "Acord"; @@ -325,7 +345,7 @@ carregat a Mastodon."; "Scene.Register.Input.Username.Placeholder" = "nom d'usuari"; "Scene.Register.LetsGetYouSetUpOnDomain" = "Anem a configurar-te a %@"; "Scene.Register.Title" = "Anem a configurar-te a %@"; -"Scene.Report.Content1" = "Hi ha alguna altre publicació que vulguis afegir a l'informe?"; +"Scene.Report.Content1" = "Hi ha algun altre tut que vulguis afegir a l'informe?"; "Scene.Report.Content2" = "Hi ha alguna cosa que els moderadors hagin de saber sobre aquest informe?"; "Scene.Report.ReportSentTitle" = "Gràcies per informar, ho investigarem."; "Scene.Report.Reported" = "REPORTAT"; @@ -336,13 +356,13 @@ carregat a Mastodon."; "Scene.Report.StepFinal.BlockUser" = "Bloca %@"; "Scene.Report.StepFinal.DontWantToSeeThis" = "No vols veure això?"; "Scene.Report.StepFinal.MuteUser" = "Silencia %@"; -"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "Ja no podran seguir ni veure les teves publicacions, però poden veure si han estat bloquejats."; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "Ja no podran seguir ni veure els teus tus, però poden veure si han estat blocats."; "Scene.Report.StepFinal.Unfollow" = "Deixa de seguir"; "Scene.Report.StepFinal.UnfollowUser" = "Deixa de seguir %@"; "Scene.Report.StepFinal.Unfollowed" = "S'ha deixat de seguir"; -"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "Quan veus alguna cosa que no t'agrada a Mastodon, pots eliminar la persona de la vostra experiència."; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "Quan veus alguna cosa que no t'agrada a Mastodon, pots eliminar la persona de la teva experiència."; "Scene.Report.StepFinal.WhileWeReviewThisYouCanTakeActionAgainstUser" = "Mentre ho revisem, pots prendre mesures contra %@"; -"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "No veuràs les seves publicacions o impulsos a la teva línia de temps personal. No sabran que han estat silenciats."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "No veuràs els seus tuts o impulsos a la teva línia de temps personal. No sabran que han estat silenciats."; "Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Hi ha res més que hauríem de saber?"; "Scene.Report.StepFour.Step4Of4" = "Pas 4 de 4"; "Scene.Report.StepOne.IDontLikeIt" = "No m'agrada"; @@ -355,10 +375,10 @@ carregat a Mastodon."; "Scene.Report.StepOne.Step1Of4" = "Pas 1 de 4"; "Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "El problema no encaixa en altres categories"; "Scene.Report.StepOne.WhatsWrongWithThisAccount" = "Quin és el problema amb aquest compte?"; -"Scene.Report.StepOne.WhatsWrongWithThisPost" = "Quin és el problema amb aquesta publicació?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "Quin és el problema amb aquest tut?"; "Scene.Report.StepOne.WhatsWrongWithThisUsername" = "Quin és el problema amb %@?"; "Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "Ets conscient que incompleix normes específiques"; -"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Hi ha alguna publicació que recolzi aquest informe?"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Hi ha alguns tuts que recolzin aquest informe?"; "Scene.Report.StepThree.SelectAllThatApply" = "Selecciona tot el que correspongui"; "Scene.Report.StepThree.Step3Of4" = "Pas 3 de 4"; "Scene.Report.StepTwo.IJustDon’tLikeIt" = "Simplement no m'agrada"; @@ -383,7 +403,7 @@ carregat a Mastodon."; "Scene.Search.Searching.Segment.All" = "Tots"; "Scene.Search.Searching.Segment.Hashtags" = "Etiquetes"; "Scene.Search.Searching.Segment.People" = "Gent"; -"Scene.Search.Searching.Segment.Posts" = "Publicacions"; +"Scene.Search.Searching.Segment.Posts" = "Tuts"; "Scene.Search.Title" = "Cerca"; "Scene.ServerPicker.Button.Category.Academia" = "acadèmia"; "Scene.ServerPicker.Button.Category.Activism" = "activisme"; @@ -409,7 +429,7 @@ carregat a Mastodon."; "Scene.ServerPicker.Label.Language" = "LLENGUATGE"; "Scene.ServerPicker.Label.Users" = "USUARIS"; "Scene.ServerPicker.Subtitle" = "Tria un servidor en funció de la teva regió, interessos o un de propòsit general. Seguiràs podent connectar amb tothom a Mastodon, independentment del servidor."; -"Scene.ServerPicker.Title" = "Mastodon està fet d'usuaris en diferents comunitats."; +"Scene.ServerPicker.Title" = "Mastodon està fet d'usuaris en diferents servidors."; "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 %@."; @@ -431,8 +451,8 @@ carregat a Mastodon."; "Scene.Settings.Section.LookAndFeel.SortaDark" = "Una Mena de Fosc"; "Scene.Settings.Section.LookAndFeel.Title" = "Aspecte i Comportament"; "Scene.Settings.Section.LookAndFeel.UseSystem" = "Usa el del Sistema"; -"Scene.Settings.Section.Notifications.Boosts" = "Ha impulsat el meu estat"; -"Scene.Settings.Section.Notifications.Favorites" = "Ha afavorit el meu estat"; +"Scene.Settings.Section.Notifications.Boosts" = "Ha impulsat el meu tut"; +"Scene.Settings.Section.Notifications.Favorites" = "Ha afavorit el meu tut"; "Scene.Settings.Section.Notifications.Follows" = "Em segueix"; "Scene.Settings.Section.Notifications.Mentions" = "M'ha mencionat"; "Scene.Settings.Section.Notifications.Title" = "Notificacions"; @@ -451,10 +471,10 @@ carregat a Mastodon."; "Scene.Settings.Section.SpicyZone.Signout" = "Tancar Sessió"; "Scene.Settings.Section.SpicyZone.Title" = "La Zona Picant"; "Scene.Settings.Title" = "Configuració"; -"Scene.SuggestionAccount.FollowExplain" = "Quan segueixes algú, veuràs les seves publicacions a Inici."; +"Scene.SuggestionAccount.FollowExplain" = "Quan segueixes algú, veuràs els seus tuts a Inici."; "Scene.SuggestionAccount.Title" = "Cerca Persones a Seguir"; -"Scene.Thread.BackTitle" = "Publicació"; -"Scene.Thread.Title" = "Publicació de %@"; +"Scene.Thread.BackTitle" = "Tut"; +"Scene.Thread.Title" = "Tut de %@"; "Scene.Welcome.GetStarted" = "Comença"; "Scene.Welcome.LogIn" = "Inicia sessió"; "Scene.Welcome.Slogan" = "Xarxa social diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.stringsdict index 947597417..615fd0c48 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.stringsdict @@ -408,7 +408,7 @@ NSStringFormatValueTypeKey ld one - fa 1 día + fa 1 dia other fa %ld dies @@ -424,7 +424,7 @@ NSStringFormatValueTypeKey ld one - fa 1h + fa 1 h other fa %ld hores @@ -440,9 +440,9 @@ NSStringFormatValueTypeKey ld one - fa 1 minut + fa 1 min other - fa %ld minuts + fa %ld min date.second.ago.abbr @@ -456,9 +456,9 @@ NSStringFormatValueTypeKey ld one - fa 1 segon + fa 1 s other - fa %ld segons + fa %ld s diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings index 4e76e20fb..5f6f124a1 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings @@ -22,6 +22,9 @@ "Common.Alerts.SignOut.Message" = "دڵنیایت دەتەوێت دەربچیت؟"; "Common.Alerts.SignOut.Title" = "دەربچۆ"; "Common.Alerts.SignUpFailure.Title" = "تۆمارکردنەکە سەرکەوتوو نەبوو"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "دەنگدانەکە کۆتایی هاتووە"; "Common.Alerts.VoteFailure.Title" = "نەتوانرا دەنگ بدرێت"; "Common.Controls.Actions.Add" = "زیادی بکە"; @@ -31,6 +34,7 @@ "Common.Controls.Actions.Compose" = "پۆست بکە"; "Common.Controls.Actions.Confirm" = "پشتڕاستی بکەوە"; "Common.Controls.Actions.Continue" = "بەردەوام بە"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "لەبەری بگرەوە"; "Common.Controls.Actions.Delete" = "بیسڕەوە"; "Common.Controls.Actions.Discard" = "وازی لێ بێنە"; @@ -59,6 +63,8 @@ "Common.Controls.Actions.SignUp" = "Create account"; "Common.Controls.Actions.Skip" = "بیپەڕێنە"; "Common.Controls.Actions.TakePhoto" = "وێنە بگرە"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "هەوڵ بدەوە"; "Common.Controls.Actions.UnblockDomain" = "%@ ئاستەنگ مەکە"; "Common.Controls.Friendship.Block" = "ئاستەنگی بکە"; @@ -100,6 +106,7 @@ "Common.Controls.Status.Actions.Menu" = "پێڕست"; "Common.Controls.Status.Actions.Reblog" = "پۆستی بکەوە"; "Common.Controls.Status.Actions.Reply" = "وەڵامی بدەوە"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "گیفەکە نیشان بدە"; "Common.Controls.Status.Actions.ShowImage" = "وێنەکە نیشان بدە"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "ڤیدیۆکە لێ بدە"; @@ -107,6 +114,8 @@ "Common.Controls.Status.Actions.Unfavorite" = "بەدڵبوونەکە بگەڕێنەوە"; "Common.Controls.Status.Actions.Unreblog" = "پۆستکردنەکە بگەڕێنەوە"; "Common.Controls.Status.ContentWarning" = "ئاگاداریی ناوەڕۆک"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "دەستی پیا بنێ بۆ نیشاندانی"; "Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; @@ -124,6 +133,10 @@ "Common.Controls.Status.Tag.Mention" = "ئاماژە"; "Common.Controls.Status.Tag.Url" = "بەستەر"; "Common.Controls.Status.TapToReveal" = "دەستی پیا بنێ بۆ نیشاندانی"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ پۆست کرایەوە"; "Common.Controls.Status.UserRepliedTo" = "لە وەڵامدا بۆ %@"; "Common.Controls.Status.Visibility.Direct" = "تەنیا بەکارهێنەرە ئاماژە پێکراوەکە دەتوانێت ئەم پۆستە ببینێت."; @@ -131,9 +144,9 @@ "Common.Controls.Status.Visibility.PrivateFromMe" = "تەنیا شوێنکەوتووەکانم دەتوانن ئەم پۆستە ببینن."; "Common.Controls.Status.Visibility.Unlisted" = "هەرکەسێک دەتوانێت ئەم پۆستە ببینێت بەڵام ناچێتە بەردەمیان."; "Common.Controls.Tabs.Home" = "ماڵەوە"; -"Common.Controls.Tabs.Notification" = "ئاگادارکردنەوەکان"; +"Common.Controls.Tabs.Notifications" = "Notifications"; "Common.Controls.Tabs.Profile" = "پرۆفایل"; -"Common.Controls.Tabs.Search" = "بگەڕێ"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "Common.Controls.Timeline.Filtered" = "پاڵێوراو"; "Common.Controls.Timeline.Header.BlockedWarning" = "ناتوانیت پرۆفایلی ئەم بەکارهێنەرە ببینیت تا ئەو کاتەی ئاستەنگەکەت لادەبات."; @@ -228,6 +241,12 @@ "Scene.Familiarfollowers.Title" = "Followers you familiar"; "Scene.Favorite.Title" = "بەدڵبووەکانت"; "Scene.FavoritedBy.Title" = "Favorited By"; +"Scene.FollowedTags.Actions.Follow" = "Follow"; +"Scene.FollowedTags.Actions.Unfollow" = "Unfollow"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "posts"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Followed Tags"; "Scene.Follower.Footer" = "شوێنکەوتووەکانی لە ڕاژەکارەکانی ترەوە نیشان نادرێت."; "Scene.Follower.Title" = "follower"; "Scene.Following.Footer" = "شوێنکەوتنەکانی بۆ هەژماری ڕاژەکارەکانی تر نیشان نادرێت."; @@ -267,6 +286,7 @@ "Scene.Profile.Dashboard.Following" = "شوێنکەوتن"; "Scene.Profile.Dashboard.Posts" = "پۆستەکان"; "Scene.Profile.Fields.AddRow" = "ڕیز زیاد بکە"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "ناوەڕۆک"; "Scene.Profile.Fields.Placeholder.Label" = "ناونیشان"; "Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/cs.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/cs.lproj/Localizable.strings index 22260e380..8a8a977b7 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/cs.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/cs.lproj/Localizable.strings @@ -22,6 +22,9 @@ Zkontrolujte prosím připojení k internetu."; "Common.Alerts.SignOut.Message" = "Opravdu se chcete odhlásit?"; "Common.Alerts.SignOut.Title" = "Odhlásit se"; "Common.Alerts.SignUpFailure.Title" = "Registrace selhala"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "Anketa skončila"; "Common.Alerts.VoteFailure.Title" = "Selhání hlasování"; "Common.Controls.Actions.Add" = "Přidat"; @@ -31,6 +34,7 @@ Zkontrolujte prosím připojení k internetu."; "Common.Controls.Actions.Compose" = "Napsat"; "Common.Controls.Actions.Confirm" = "Potvrdit"; "Common.Controls.Actions.Continue" = "Pokračovat"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "Kopírovat fotografii"; "Common.Controls.Actions.Delete" = "Smazat"; "Common.Controls.Actions.Discard" = "Zahodit"; @@ -59,6 +63,8 @@ Zkontrolujte prosím připojení k internetu."; "Common.Controls.Actions.SignUp" = "Vytvořit účet"; "Common.Controls.Actions.Skip" = "Přeskočit"; "Common.Controls.Actions.TakePhoto" = "Vyfotit"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "Zkusit znovu"; "Common.Controls.Actions.UnblockDomain" = "Odblokovat %@"; "Common.Controls.Friendship.Block" = "Blokovat"; @@ -94,12 +100,13 @@ Zkontrolujte prosím připojení k internetu."; "Common.Controls.Keyboard.Timeline.ReplyStatus" = "Odpovědět na příspěvek"; "Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Přepnout varování obsahu"; "Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Toggle Favorite on Post"; -"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Toggle Reblog on Post"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Přepnout Reblog na příspěvku"; "Common.Controls.Status.Actions.Favorite" = "Oblíbit"; "Common.Controls.Status.Actions.Hide" = "Skrýt"; "Common.Controls.Status.Actions.Menu" = "Nabídka"; "Common.Controls.Status.Actions.Reblog" = "Boostnout"; "Common.Controls.Status.Actions.Reply" = "Odpovědět"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "Zobrazit GIF"; "Common.Controls.Status.Actions.ShowImage" = "Zobrazit obrázek"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Zobrazit video přehrávač"; @@ -107,6 +114,8 @@ Zkontrolujte prosím připojení k internetu."; "Common.Controls.Status.Actions.Unfavorite" = "Odebrat z oblízených"; "Common.Controls.Status.Actions.Unreblog" = "Undo reblog"; "Common.Controls.Status.ContentWarning" = "Varování o obsahu"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "Klepnutím kdekoli zobrazíte"; "Common.Controls.Status.MetaEntity.Email" = "E-mailová adresa: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; @@ -124,6 +133,10 @@ Zkontrolujte prosím připojení k internetu."; "Common.Controls.Status.Tag.Mention" = "Zmínka"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Klepnutím zobrazit"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ reblogged"; "Common.Controls.Status.UserRepliedTo" = "Odpověděl %@"; "Common.Controls.Status.Visibility.Direct" = "Pouze zmíněný uživatel může vidět tento příspěvek."; @@ -131,9 +144,9 @@ Zkontrolujte prosím připojení k internetu."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Pouze moji sledující mohou vidět tento příspěvek."; "Common.Controls.Status.Visibility.Unlisted" = "Každý může vidět tento příspěvek, ale nezobrazovat ve veřejné časové ose."; "Common.Controls.Tabs.Home" = "Domů"; -"Common.Controls.Tabs.Notification" = "Oznamování"; +"Common.Controls.Tabs.Notifications" = "Oznámení"; "Common.Controls.Tabs.Profile" = "Profil"; -"Common.Controls.Tabs.Search" = "Hledat"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "Common.Controls.Timeline.Filtered" = "Filtrováno"; "Common.Controls.Timeline.Header.BlockedWarning" = "Nemůžeš zobrazit profil tohoto uživatele, dokud tě neodblokují."; "Common.Controls.Timeline.Header.BlockingWarning" = "Nemůžete zobrazit profil tohoto uživatele, dokud ho neodblokujete. @@ -225,6 +238,12 @@ nahrán do Mastodonu."; "Scene.Familiarfollowers.Title" = "Sledující, které znáte"; "Scene.Favorite.Title" = "Vaše oblíbené"; "Scene.FavoritedBy.Title" = "Oblíben"; +"Scene.FollowedTags.Actions.Follow" = "Sledovat"; +"Scene.FollowedTags.Actions.Unfollow" = "Přestat sledovat"; +"Scene.FollowedTags.Header.Participants" = "účastníci"; +"Scene.FollowedTags.Header.Posts" = "příspěvky"; +"Scene.FollowedTags.Header.PostsToday" = "příspěvky dnes"; +"Scene.FollowedTags.Title" = "Sledované štítky"; "Scene.Follower.Footer" = "Sledující z jiných serverů nejsou zobrazeni."; "Scene.Follower.Title" = "sledující"; "Scene.Following.Footer" = "Sledování z jiných serverů není zobrazeno."; @@ -264,6 +283,7 @@ nahrán do Mastodonu."; "Scene.Profile.Dashboard.Following" = "sledování"; "Scene.Profile.Dashboard.Posts" = "příspěvky"; "Scene.Profile.Fields.AddRow" = "Přidat řádek"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "Obsah"; "Scene.Profile.Fields.Placeholder.Label" = "Označení"; "Scene.Profile.Fields.Verified.Long" = "Vlastnictví tohoto odkazu bylo zkontrolováno na %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings index 29f3d16f5..74dbaeea6 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings @@ -5,7 +5,7 @@ "Common.Alerts.Common.PleaseTryAgain" = "Bitte versuche es erneut."; "Common.Alerts.Common.PleaseTryAgainLater" = "Bitte versuche es später nochmal."; "Common.Alerts.DeletePost.Message" = "Bist du dir sicher, dass du diesen Beitrag löschen willst?"; -"Common.Alerts.DeletePost.Title" = "Bist du dir sicher, dass du diesen Beitrag löschen möchtest?"; +"Common.Alerts.DeletePost.Title" = "Beiträge löschen"; "Common.Alerts.DiscardPostContent.Message" = "Bestätige, um den Beitrag zu verwerfen."; "Common.Alerts.DiscardPostContent.Title" = "Entwurf verwerfen"; "Common.Alerts.EditProfileFailure.Message" = "Profil kann nicht bearbeitet werden. Bitte versuche es erneut."; @@ -22,6 +22,9 @@ Bitte überprüfe deine Internetverbindung."; "Common.Alerts.SignOut.Message" = "Bist du sicher, dass du dich abmelden möchten?"; "Common.Alerts.SignOut.Title" = "Abmelden"; "Common.Alerts.SignUpFailure.Title" = "Registrierungsfehler"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Übersetzung fehlgeschlagen. Möglicherweise hat der/die Administrator*in die Übersetzungen auf diesem Server nicht aktiviert oder dieser Server läuft mit einer älteren Version von Mastodon, in der Übersetzungen noch nicht unterstützt wurden."; +"Common.Alerts.TranslationFailed.Title" = "Hinweis"; "Common.Alerts.VoteFailure.PollEnded" = "Die Umfrage ist beendet"; "Common.Alerts.VoteFailure.Title" = "Fehler bei Abstimmung"; "Common.Controls.Actions.Add" = "Hinzufügen"; @@ -30,13 +33,14 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Actions.Cancel" = "Abbrechen"; "Common.Controls.Actions.Compose" = "Neue Nachricht"; "Common.Controls.Actions.Confirm" = "Bestätigen"; -"Common.Controls.Actions.Continue" = "Fortfahren"; +"Common.Controls.Actions.Continue" = "Weiter"; +"Common.Controls.Actions.Copy" = "Kopieren"; "Common.Controls.Actions.CopyPhoto" = "Foto kopieren"; "Common.Controls.Actions.Delete" = "Löschen"; "Common.Controls.Actions.Discard" = "Verwerfen"; "Common.Controls.Actions.Done" = "Fertig"; "Common.Controls.Actions.Edit" = "Bearbeiten"; -"Common.Controls.Actions.FindPeople" = "Finde Personen zum Folgen"; +"Common.Controls.Actions.FindPeople" = "Personen zum Folgen finden"; "Common.Controls.Actions.ManuallySearch" = "Stattdessen manuell suchen"; "Common.Controls.Actions.Next" = "Weiter"; "Common.Controls.Actions.Ok" = "OK"; @@ -59,6 +63,8 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Actions.SignUp" = "Konto erstellen"; "Common.Controls.Actions.Skip" = "Überspringen"; "Common.Controls.Actions.TakePhoto" = "Foto aufnehmen"; +"Common.Controls.Actions.TranslatePost.Title" = "Von %@ übersetzen"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unbekannt"; "Common.Controls.Actions.TryAgain" = "Nochmals versuchen"; "Common.Controls.Actions.UnblockDomain" = "Blockierung von %@ aufheben"; "Common.Controls.Friendship.Block" = "Blockieren"; @@ -67,14 +73,14 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Friendship.Blocked" = "Blockiert"; "Common.Controls.Friendship.EditInfo" = "Information bearbeiten"; "Common.Controls.Friendship.Follow" = "Folgen"; -"Common.Controls.Friendship.Following" = "Folge Ich"; -"Common.Controls.Friendship.HideReblogs" = "Reblogs ausblenden"; +"Common.Controls.Friendship.Following" = "Gefolgt"; +"Common.Controls.Friendship.HideReblogs" = "Teilen ausblenden"; "Common.Controls.Friendship.Mute" = "Stummschalten"; "Common.Controls.Friendship.MuteUser" = "%@ stummschalten"; "Common.Controls.Friendship.Muted" = "Stummgeschaltet"; "Common.Controls.Friendship.Pending" = "In Warteschlange"; "Common.Controls.Friendship.Request" = "Anfragen"; -"Common.Controls.Friendship.ShowReblogs" = "Reblogs anzeigen"; +"Common.Controls.Friendship.ShowReblogs" = "Teilen anzeigen"; "Common.Controls.Friendship.Unblock" = "Blockierung aufheben"; "Common.Controls.Friendship.UnblockUser" = "Blockierung von %@ aufheben"; "Common.Controls.Friendship.Unmute" = "Nicht mehr stummschalten"; @@ -100,6 +106,7 @@ 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.ShareLinkInPost" = "Link im Beitrag teilen"; "Common.Controls.Status.Actions.ShowGif" = "GIF anzeigen"; "Common.Controls.Status.Actions.ShowImage" = "Bild anzeigen"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Zeige Video-Player"; @@ -107,10 +114,12 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Status.Actions.Unfavorite" = "Aus Favoriten entfernen"; "Common.Controls.Status.Actions.Unreblog" = "Nicht mehr teilen"; "Common.Controls.Status.ContentWarning" = "Inhaltswarnung"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Eingebettetes laden"; "Common.Controls.Status.MediaContentWarning" = "Tippe irgendwo zum Anzeigen"; -"Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; +"Common.Controls.Status.MetaEntity.Email" = "E-Mail-Adresse: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; -"Common.Controls.Status.MetaEntity.Mention" = "Show Profile: %@"; +"Common.Controls.Status.MetaEntity.Mention" = "Profil anzeigen: %@"; "Common.Controls.Status.MetaEntity.Url" = "Link: %@"; "Common.Controls.Status.Poll.Closed" = "Beendet"; "Common.Controls.Status.Poll.Vote" = "Abstimmen"; @@ -124,16 +133,20 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Status.Tag.Mention" = "Erwähnung"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Zum Anzeigen tippen"; +"Common.Controls.Status.Translation.ShowOriginal" = "Original anzeigen"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unbekannt"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "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."; -"Common.Controls.Status.Visibility.Private" = "Nur Follower des Authors können diesen Beitrag sehen."; -"Common.Controls.Status.Visibility.PrivateFromMe" = "Nur meine Follower können diesen Beitrag sehen."; +"Common.Controls.Status.Visibility.Private" = "Nur die, die dem Autor folgen, können diesen Beitrag sehen."; +"Common.Controls.Status.Visibility.PrivateFromMe" = "Nur die, die mir folgen, können diesen Beitrag sehen."; "Common.Controls.Status.Visibility.Unlisted" = "Jeder kann diesen Post sehen, aber nicht in der öffentlichen Timeline zeigen."; "Common.Controls.Tabs.Home" = "Startseite"; -"Common.Controls.Tabs.Notification" = "Benachrichtigungen"; +"Common.Controls.Tabs.Notifications" = "Mitteilungen"; "Common.Controls.Tabs.Profile" = "Profil"; -"Common.Controls.Tabs.Search" = "Suche"; +"Common.Controls.Tabs.SearchAndExplore" = "Suchen und Entdecken"; "Common.Controls.Timeline.Filtered" = "Gefiltert"; "Common.Controls.Timeline.Header.BlockedWarning" = "Das Profil dieses Benutzers kann nicht angezeigt werden, bis er dich entsperrt."; @@ -149,7 +162,7 @@ solange du diesen Benutzer nicht entsperrst. Dein Profil sieht für diesen Benutzer auch so aus."; "Common.Controls.Timeline.Header.UserSuspendedWarning" = "Das Konto von %@ wurde gesperrt."; "Common.Controls.Timeline.Loader.LoadMissingPosts" = "Fehlende Beiträge laden"; -"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Lade fehlende Beiträge..."; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Fehlende Beiträge werden geladen …"; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Weitere Antworten anzeigen"; "Common.Controls.Timeline.Timestamp.Now" = "Gerade"; "Scene.AccountList.AddAccount" = "Konto hinzufügen"; @@ -161,26 +174,26 @@ Dein Profil sieht für diesen Benutzer auch so aus."; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Benutzerdefinierter Emojiwähler"; "Scene.Compose.Accessibility.DisableContentWarning" = "Inhaltswarnung ausschalten"; "Scene.Compose.Accessibility.EnableContentWarning" = "Inhaltswarnung einschalten"; -"Scene.Compose.Accessibility.PostOptions" = "Post Options"; +"Scene.Compose.Accessibility.PostOptions" = "Beitragsoptionen"; "Scene.Compose.Accessibility.PostVisibilityMenu" = "Sichtbarkeitsmenü"; -"Scene.Compose.Accessibility.PostingAs" = "Posting as %@"; +"Scene.Compose.Accessibility.PostingAs" = "Veröffentlichen als %@"; "Scene.Compose.Accessibility.RemovePoll" = "Umfrage entfernen"; "Scene.Compose.Attachment.AttachmentBroken" = "Dieses %@ scheint defekt zu sein und kann nicht auf Mastodon hochgeladen werden."; "Scene.Compose.Attachment.AttachmentTooLarge" = "Anhang zu groß"; "Scene.Compose.Attachment.CanNotRecognizeThisMediaAttachment" = "Medienanhang wurde nicht erkannt"; -"Scene.Compose.Attachment.CompressingState" = "Komprimieren..."; -"Scene.Compose.Attachment.DescriptionPhoto" = "Für Menschen mit Sehbehinderung beschreiben..."; -"Scene.Compose.Attachment.DescriptionVideo" = "Für Menschen mit Sehbehinderung beschreiben..."; +"Scene.Compose.Attachment.CompressingState" = "wird komprimiert …"; +"Scene.Compose.Attachment.DescriptionPhoto" = "Für Menschen mit Sehbehinderung beschreiben …"; +"Scene.Compose.Attachment.DescriptionVideo" = "Für Menschen mit Sehbehinderung beschreiben …"; "Scene.Compose.Attachment.LoadFailed" = "Laden fehlgeschlagen"; "Scene.Compose.Attachment.Photo" = "Foto"; -"Scene.Compose.Attachment.ServerProcessingState" = "Serververarbeitung..."; +"Scene.Compose.Attachment.ServerProcessingState" = "Serververarbeitung …"; "Scene.Compose.Attachment.UploadFailed" = "Upload fehlgeschlagen"; "Scene.Compose.Attachment.Video" = "Video"; "Scene.Compose.AutoComplete.SpaceToAdd" = "Leerzeichen um hinzuzufügen"; "Scene.Compose.ComposeAction" = "Veröffentlichen"; "Scene.Compose.ContentInputPlaceholder" = "Tippe oder füge ein, was dir am Herzen liegt"; -"Scene.Compose.ContentWarning.Placeholder" = "Schreibe eine Inhaltswarnung hier..."; +"Scene.Compose.ContentWarning.Placeholder" = "Hier eine Inhaltswarnung schreiben …"; "Scene.Compose.Keyboard.AppendAttachmentEntry" = "Anhang hinzufügen - %@"; "Scene.Compose.Keyboard.DiscardPost" = "Beitrag verwerfen"; "Scene.Compose.Keyboard.PublishPost" = "Beitrag veröffentlichen"; @@ -213,7 +226,7 @@ kann nicht auf Mastodon hochgeladen werden."; "Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "E-Mail erneut versenden"; "Scene.ConfirmEmail.DontReceiveEmail.Title" = "Bitte überprüfe deine E-Mails"; "Scene.ConfirmEmail.OpenEmailApp.Description" = "Wir haben dir gerade eine E-Mail geschickt. Überprüfe deinen Spam-Ordner, falls du es noch nicht getan hast."; -"Scene.ConfirmEmail.OpenEmailApp.Mail" = "Mail"; +"Scene.ConfirmEmail.OpenEmailApp.Mail" = "E-Mail"; "Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "E-Mail-Client öffnen"; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Überprüfe deinen Posteingang."; "Scene.ConfirmEmail.Subtitle" = "Schaue kurz in dein E-Mail-Postfach und tippe den Link an, den wir dir gesendet haben."; @@ -226,19 +239,25 @@ kann nicht auf Mastodon hochgeladen werden."; "Scene.Discovery.Tabs.News" = "Nachrichten"; "Scene.Discovery.Tabs.Posts" = "Beiträge"; "Scene.Familiarfollowers.FollowedByNames" = "Gefolgt von %@"; -"Scene.Familiarfollowers.Title" = "Follower, die dir bekannt vorkommen"; +"Scene.Familiarfollowers.Title" = "Folgende, die du kennst"; "Scene.Favorite.Title" = "Deine Favoriten"; "Scene.FavoritedBy.Title" = "Favorisiert von"; -"Scene.Follower.Footer" = "Folger, die nicht auf deinem Server registriert sind, werden nicht angezeigt."; -"Scene.Follower.Title" = "Follower"; +"Scene.FollowedTags.Actions.Follow" = "Folgen"; +"Scene.FollowedTags.Actions.Unfollow" = "Entfolgen"; +"Scene.FollowedTags.Header.Participants" = "Teilnehmer*innen"; +"Scene.FollowedTags.Header.Posts" = "Beiträge"; +"Scene.FollowedTags.Header.PostsToday" = "Beiträge heute"; +"Scene.FollowedTags.Title" = "Gefolgte Hashtags"; +"Scene.Follower.Footer" = "Folgende, die nicht auf deinem Server registriert sind, werden nicht angezeigt."; +"Scene.Follower.Title" = "Folgende"; "Scene.Following.Footer" = "Gefolgte, die nicht auf deinem Server registriert sind, werden nicht angezeigt."; -"Scene.Following.Title" = "Folgende"; +"Scene.Following.Title" = "Gefolgte"; "Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Zum Scrollen nach oben tippen und zum vorherigen Ort erneut tippen"; "Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo-Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Neue Beiträge anzeigen"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; "Scene.HomeTimeline.NavigationBarState.Published" = "Veröffentlicht!"; -"Scene.HomeTimeline.NavigationBarState.Publishing" = "Beitrag wird veröffentlicht..."; +"Scene.HomeTimeline.NavigationBarState.Publishing" = "Beitrag wird veröffentlicht …"; "Scene.HomeTimeline.Title" = "Startseite"; "Scene.Login.ServerSearchField.Placeholder" = "URL eingeben oder nach Server suchen"; "Scene.Login.Subtitle" = "Melden Sie sich auf dem Server an, auf dem Sie Ihr Konto erstellt haben."; @@ -268,6 +287,7 @@ kann nicht auf Mastodon hochgeladen werden."; "Scene.Profile.Dashboard.Following" = "Gefolgte"; "Scene.Profile.Dashboard.Posts" = "Beiträge"; "Scene.Profile.Fields.AddRow" = "Zeile hinzufügen"; +"Scene.Profile.Fields.Joined" = "Beigetreten"; "Scene.Profile.Fields.Placeholder.Content" = "Inhalt"; "Scene.Profile.Fields.Placeholder.Label" = "Bezeichnung"; "Scene.Profile.Fields.Verified.Long" = "Besitz des Links wurde überprüft am %@"; @@ -275,12 +295,12 @@ kann nicht auf Mastodon hochgeladen werden."; "Scene.Profile.Header.FollowsYou" = "Folgt dir"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Bestätige %@ zu blockieren"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Konto blockieren"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Confirm to hide reblogs"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Reblogs ausblenden"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Bestätigen, um Teilen auszublenden"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Teilen ausblenden"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Bestätige %@ stumm zu schalten"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Konto stummschalten"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Bestätigen um Reblogs anzuzeigen"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Reblogs anzeigen"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Bestätigen, um Teilen anzuzeigen"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Teilen anzeigen"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Bestätige %@ zu entsperren"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Konto entsperren"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Bestätige um %@ nicht mehr stummzuschalten"; @@ -368,7 +388,7 @@ kann nicht auf Mastodon hochgeladen werden."; "Scene.Report.TextPlaceholder" = "Zusätzliche Kommentare eingeben oder einfügen"; "Scene.Report.Title" = "%@ melden"; "Scene.Report.TitleReport" = "Melden"; -"Scene.Search.Recommend.Accounts.Description" = "Vielleicht gefallen dir diese Benutzer"; +"Scene.Search.Recommend.Accounts.Description" = "Vielleicht gefallen dir diese Konten"; "Scene.Search.Recommend.Accounts.Follow" = "Folgen"; "Scene.Search.Recommend.Accounts.Title" = "Konten, die dir gefallen könnten"; "Scene.Search.Recommend.ButtonText" = "Alle anzeigen"; @@ -402,7 +422,7 @@ kann nicht auf Mastodon hochgeladen werden."; "Scene.ServerPicker.Button.SeeLess" = "Weniger anzeigen"; "Scene.ServerPicker.Button.SeeMore" = "Mehr anzeigen"; "Scene.ServerPicker.EmptyState.BadNetwork" = "Beim Laden der Daten ist etwas schief gelaufen. Überprüfe deine Internetverbindung."; -"Scene.ServerPicker.EmptyState.FindingServers" = "Verfügbare Server werden gesucht..."; +"Scene.ServerPicker.EmptyState.FindingServers" = "Verfügbare Server werden gesucht …"; "Scene.ServerPicker.EmptyState.NoResults" = "Keine Ergebnisse"; "Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Suche nach einer Community oder gib eine URL ein"; "Scene.ServerPicker.Label.Category" = "KATEGORIE"; @@ -452,7 +472,7 @@ beliebigen Server."; "Scene.Settings.Section.SpicyZone.Signout" = "Abmelden"; "Scene.Settings.Section.SpicyZone.Title" = "Der Gefährliche Bereich"; "Scene.Settings.Title" = "Einstellungen"; -"Scene.SuggestionAccount.FollowExplain" = "Wenn du jemandem folgst, dann siehst du deren Beiträge in deinem Home-Feed."; +"Scene.SuggestionAccount.FollowExplain" = "Sobald du anderen folgst, siehst du deren Beiträge in deinem Home-Feed."; "Scene.SuggestionAccount.Title" = "Finde Personen zum Folgen"; "Scene.Thread.BackTitle" = "Beitrag"; "Scene.Thread.Title" = "Beitrag von %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict index 1965fd02b..9d07f80d1 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict @@ -37,7 +37,7 @@ a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Noch %#@character_count@ übrig + Noch %#@character_count@ Zeichen übrig character_count NSStringFormatSpecTypeKey @@ -53,7 +53,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + %#@character_count@ übrig character_count NSStringFormatSpecTypeKey @@ -61,9 +61,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 Zeichen other - %ld characters + %ld Zeichen plural.count.followed_by_and_mutual diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings index 2a3f1efbf..3ba305a4b 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -22,6 +22,9 @@ Please check your internet connection."; "Common.Alerts.SignOut.Message" = "Are you sure you want to sign out?"; "Common.Alerts.SignOut.Title" = "Sign Out"; "Common.Alerts.SignUpFailure.Title" = "Sign Up Failure"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "The poll has ended"; "Common.Alerts.VoteFailure.Title" = "Vote Failure"; "Common.Controls.Actions.Add" = "Add"; @@ -31,6 +34,7 @@ Please check your internet connection."; "Common.Controls.Actions.Compose" = "Compose"; "Common.Controls.Actions.Confirm" = "Confirm"; "Common.Controls.Actions.Continue" = "Continue"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "Copy Photo"; "Common.Controls.Actions.Delete" = "Delete"; "Common.Controls.Actions.Discard" = "Discard"; @@ -100,6 +104,7 @@ 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.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "Show GIF"; "Common.Controls.Status.Actions.ShowImage" = "Show image"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; @@ -107,6 +112,8 @@ Please check your internet connection."; "Common.Controls.Status.Actions.Unfavorite" = "Unfavorite"; "Common.Controls.Status.Actions.Unreblog" = "Undo reblog"; "Common.Controls.Status.ContentWarning" = "Content Warning"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "Tap anywhere to reveal"; "Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; @@ -124,6 +131,10 @@ Please check your internet connection."; "Common.Controls.Status.Tag.Mention" = "Mention"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ reblogged"; "Common.Controls.Status.UserRepliedTo" = "Replied to %@"; "Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; @@ -131,9 +142,9 @@ Please check your internet connection."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Only my followers can see this post."; "Common.Controls.Status.Visibility.Unlisted" = "Everyone can see this post but not display in the public timeline."; "Common.Controls.Tabs.Home" = "Home"; -"Common.Controls.Tabs.Notification" = "Notification"; +"Common.Controls.Tabs.Notifications" = "Notifications"; "Common.Controls.Tabs.Profile" = "Profile"; -"Common.Controls.Tabs.Search" = "Search"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "Common.Controls.Timeline.Filtered" = "Filtered"; "Common.Controls.Timeline.Header.BlockedWarning" = "You can’t view this user’s profile until they unblock you."; @@ -229,12 +240,18 @@ uploaded to Mastodon."; "Scene.Familiarfollowers.Title" = "Followers you familiar"; "Scene.Favorite.Title" = "Your Favorites"; "Scene.FavoritedBy.Title" = "Favorited By"; +"Scene.FollowedTags.Actions.Follow" = "Follow"; +"Scene.FollowedTags.Actions.Unfollow" = "Unfollow"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "posts"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Followed Tags"; "Scene.Follower.Footer" = "Followers from other servers are not displayed."; "Scene.Follower.Title" = "follower"; "Scene.Following.Footer" = "Follows from other servers are not displayed."; "Scene.Following.Title" = "following"; "Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; -"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Mastodon"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "See new posts"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; "Scene.HomeTimeline.NavigationBarState.Published" = "Published!"; @@ -268,6 +285,7 @@ uploaded to Mastodon."; "Scene.Profile.Dashboard.Following" = "following"; "Scene.Profile.Dashboard.Posts" = "posts"; "Scene.Profile.Fields.AddRow" = "Add Row"; +"Scene.Profile.Fields.Joined" = "Liitytty"; "Scene.Profile.Fields.Placeholder.Content" = "Content"; "Scene.Profile.Fields.Placeholder.Label" = "Label"; "Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.stringsdict index 297e6675a..788eb95fc 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.stringsdict @@ -15,7 +15,7 @@ one 1 unread notification other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds @@ -60,14 +60,8 @@ NSStringPluralRuleType NSStringFormatValueTypeKey ld - zero - no characters one 1 character - few - %ld characters - many - %ld characters other %ld characters diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings index b2cb18954..d9d6a6ff6 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings @@ -22,6 +22,9 @@ Por favor, revise su conexión a internet."; "Common.Alerts.SignOut.Message" = "¿Estás seguro de que deseas cerrar la sesión?"; "Common.Alerts.SignOut.Title" = "Cerrar Sesión"; "Common.Alerts.SignUpFailure.Title" = "Error al registrarse"; +"Common.Alerts.TranslationFailed.Button" = "Aceptar"; +"Common.Alerts.TranslationFailed.Message" = "Error al traducir. Tal vez el administrador no ha habilitado las traducciones en este servidor o este servidor está ejecutando una versión antigua de Mastodon donde las traducciones aún no están soportadas."; +"Common.Alerts.TranslationFailed.Title" = "Nota"; "Common.Alerts.VoteFailure.PollEnded" = "La encuesta ha terminado"; "Common.Alerts.VoteFailure.Title" = "Voto fallido"; "Common.Controls.Actions.Add" = "Añadir"; @@ -31,6 +34,7 @@ Por favor, revise su conexión a internet."; "Common.Controls.Actions.Compose" = "Redactar"; "Common.Controls.Actions.Confirm" = "Confirmar"; "Common.Controls.Actions.Continue" = "Continuar"; +"Common.Controls.Actions.Copy" = "Copiar"; "Common.Controls.Actions.CopyPhoto" = "Copiar foto"; "Common.Controls.Actions.Delete" = "Borrar"; "Common.Controls.Actions.Discard" = "Descartar"; @@ -55,10 +59,12 @@ Por favor, revise su conexión a internet."; "Common.Controls.Actions.Share" = "Compartir"; "Common.Controls.Actions.SharePost" = "Compartir publicación"; "Common.Controls.Actions.ShareUser" = "Compartir %@"; -"Common.Controls.Actions.SignIn" = "Log in"; -"Common.Controls.Actions.SignUp" = "Create account"; +"Common.Controls.Actions.SignIn" = "Iniciar sesión"; +"Common.Controls.Actions.SignUp" = "Crear cuenta"; "Common.Controls.Actions.Skip" = "Omitir"; "Common.Controls.Actions.TakePhoto" = "Tomar foto"; +"Common.Controls.Actions.TranslatePost.Title" = "Traducir desde %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Desconocido"; "Common.Controls.Actions.TryAgain" = "Inténtalo de nuevo"; "Common.Controls.Actions.UnblockDomain" = "Desbloquear %@"; "Common.Controls.Friendship.Block" = "Bloquear"; @@ -68,13 +74,13 @@ Por favor, revise su conexión a internet."; "Common.Controls.Friendship.EditInfo" = "Editar Info"; "Common.Controls.Friendship.Follow" = "Seguir"; "Common.Controls.Friendship.Following" = "Siguiendo"; -"Common.Controls.Friendship.HideReblogs" = "Hide Reblogs"; +"Common.Controls.Friendship.HideReblogs" = "Ocultar reblogs"; "Common.Controls.Friendship.Mute" = "Silenciar"; "Common.Controls.Friendship.MuteUser" = "Silenciar a %@"; "Common.Controls.Friendship.Muted" = "Silenciado"; "Common.Controls.Friendship.Pending" = "Pendiente"; "Common.Controls.Friendship.Request" = "Solicitud"; -"Common.Controls.Friendship.ShowReblogs" = "Show Reblogs"; +"Common.Controls.Friendship.ShowReblogs" = "Mostrar reblogs"; "Common.Controls.Friendship.Unblock" = "Desbloquear"; "Common.Controls.Friendship.UnblockUser" = "Desbloquear a %@"; "Common.Controls.Friendship.Unmute" = "Desmutear"; @@ -100,6 +106,7 @@ 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.ShareLinkInPost" = "Compartir enlace en publicación"; "Common.Controls.Status.Actions.ShowGif" = "Mostrar GIF"; "Common.Controls.Status.Actions.ShowImage" = "Mostrar imagen"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Mostrar reproductor de vídeo"; @@ -107,11 +114,13 @@ Por favor, revise su conexión a internet."; "Common.Controls.Status.Actions.Unfavorite" = "No favorito"; "Common.Controls.Status.Actions.Unreblog" = "Deshacer reblogueo"; "Common.Controls.Status.ContentWarning" = "Advertencia de Contenido"; +"Common.Controls.Status.LinkViaUser" = "%@ vía %@"; +"Common.Controls.Status.LoadEmbed" = "Cargar incrustado"; "Common.Controls.Status.MediaContentWarning" = "Pulsa en cualquier sitio para mostrar"; -"Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; -"Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; -"Common.Controls.Status.MetaEntity.Mention" = "Show Profile: %@"; -"Common.Controls.Status.MetaEntity.Url" = "Link: %@"; +"Common.Controls.Status.MetaEntity.Email" = "Dirección de correo electrónico: %@"; +"Common.Controls.Status.MetaEntity.Hashtag" = "Etiqueta: %@"; +"Common.Controls.Status.MetaEntity.Mention" = "Mostrar Perfil: %@"; +"Common.Controls.Status.MetaEntity.Url" = "Enlace: %@"; "Common.Controls.Status.Poll.Closed" = "Cerrado"; "Common.Controls.Status.Poll.Vote" = "Vota"; "Common.Controls.Status.SensitiveContent" = "Contenido sensible"; @@ -124,6 +133,10 @@ Por favor, revise su conexión a internet."; "Common.Controls.Status.Tag.Mention" = "Mención"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Tocar para revelar"; +"Common.Controls.Status.Translation.ShowOriginal" = "Mostrar Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Desconocido"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "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."; @@ -131,9 +144,9 @@ Por favor, revise su conexión a internet."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Sólo mis seguidores pueden ver este mensaje."; "Common.Controls.Status.Visibility.Unlisted" = "Todo el mundo puede ver este post pero no mostrar en la línea de tiempo pública."; "Common.Controls.Tabs.Home" = "Inicio"; -"Common.Controls.Tabs.Notification" = "Notificación"; +"Common.Controls.Tabs.Notifications" = "Notificaciones"; "Common.Controls.Tabs.Profile" = "Perfil"; -"Common.Controls.Tabs.Search" = "Buscar"; +"Common.Controls.Tabs.SearchAndExplore" = "Buscar y explorar"; "Common.Controls.Timeline.Filtered" = "Filtrado"; "Common.Controls.Timeline.Header.BlockedWarning" = "No puedes ver el perfil de este usuario hasta que te desbloquee."; @@ -155,27 +168,27 @@ Tu perfil se ve así para él."; "Scene.AccountList.AddAccount" = "Añadir cuenta"; "Scene.AccountList.DismissAccountSwitcher" = "Descartar el selector de cuentas"; "Scene.AccountList.TabBarHint" = "Perfil seleccionado actualmente: %@. Haz un doble toque y mantén pulsado para mostrar el selector de cuentas"; -"Scene.Bookmark.Title" = "Bookmarks"; +"Scene.Bookmark.Title" = "Marcadores"; "Scene.Compose.Accessibility.AppendAttachment" = "Añadir Adjunto"; "Scene.Compose.Accessibility.AppendPoll" = "Añadir Encuesta"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Selector de Emojis Personalizados"; "Scene.Compose.Accessibility.DisableContentWarning" = "Desactivar Advertencia de Contenido"; "Scene.Compose.Accessibility.EnableContentWarning" = "Activar Advertencia de Contenido"; -"Scene.Compose.Accessibility.PostOptions" = "Post Options"; +"Scene.Compose.Accessibility.PostOptions" = "Opciones de Publicación"; "Scene.Compose.Accessibility.PostVisibilityMenu" = "Menú de Visibilidad de la Publicación"; -"Scene.Compose.Accessibility.PostingAs" = "Posting as %@"; +"Scene.Compose.Accessibility.PostingAs" = "Publicado como %@"; "Scene.Compose.Accessibility.RemovePoll" = "Eliminar Encuesta"; "Scene.Compose.Attachment.AttachmentBroken" = "Este %@ está roto y no puede subirse a Mastodon."; -"Scene.Compose.Attachment.AttachmentTooLarge" = "Attachment too large"; -"Scene.Compose.Attachment.CanNotRecognizeThisMediaAttachment" = "Can not recognize this media attachment"; -"Scene.Compose.Attachment.CompressingState" = "Compressing..."; +"Scene.Compose.Attachment.AttachmentTooLarge" = "Adjunto demasiado grande"; +"Scene.Compose.Attachment.CanNotRecognizeThisMediaAttachment" = "No se puede reconocer este archivo adjunto"; +"Scene.Compose.Attachment.CompressingState" = "Comprimiendo..."; "Scene.Compose.Attachment.DescriptionPhoto" = "Describe la foto para los usuarios con dificultad visual..."; "Scene.Compose.Attachment.DescriptionVideo" = "Describe el vídeo para los usuarios con dificultad visual..."; -"Scene.Compose.Attachment.LoadFailed" = "Load Failed"; +"Scene.Compose.Attachment.LoadFailed" = "Carga fallida"; "Scene.Compose.Attachment.Photo" = "foto"; -"Scene.Compose.Attachment.ServerProcessingState" = "Server Processing..."; -"Scene.Compose.Attachment.UploadFailed" = "Upload Failed"; +"Scene.Compose.Attachment.ServerProcessingState" = "Procesando en el servidor..."; +"Scene.Compose.Attachment.UploadFailed" = "Error al cargar"; "Scene.Compose.Attachment.Video" = "vídeo"; "Scene.Compose.AutoComplete.SpaceToAdd" = "Espacio para añadir"; "Scene.Compose.ComposeAction" = "Publicar"; @@ -196,8 +209,8 @@ subirse a Mastodon."; "Scene.Compose.Poll.OptionNumber" = "Opción %ld"; "Scene.Compose.Poll.SevenDays" = "7 Días"; "Scene.Compose.Poll.SixHours" = "6 Horas"; -"Scene.Compose.Poll.ThePollHasEmptyOption" = "The poll has empty option"; -"Scene.Compose.Poll.ThePollIsInvalid" = "The poll is invalid"; +"Scene.Compose.Poll.ThePollHasEmptyOption" = "La encuesta tiene una opción vacía"; +"Scene.Compose.Poll.ThePollIsInvalid" = "La encuesta no es válida"; "Scene.Compose.Poll.ThirtyMinutes" = "30 minutos"; "Scene.Compose.Poll.ThreeDays" = "4 Días"; "Scene.Compose.ReplyingToUser" = "en respuesta a %@"; @@ -230,6 +243,12 @@ pulsa en el enlace para confirmar tu cuenta."; "Scene.Familiarfollowers.Title" = "Seguidores que conoces"; "Scene.Favorite.Title" = "Tus Favoritos"; "Scene.FavoritedBy.Title" = "Hecho favorito por"; +"Scene.FollowedTags.Actions.Follow" = "Seguir"; +"Scene.FollowedTags.Actions.Unfollow" = "Dejar de seguir"; +"Scene.FollowedTags.Header.Participants" = "participantes"; +"Scene.FollowedTags.Header.Posts" = "publicaciones"; +"Scene.FollowedTags.Header.PostsToday" = "publicaciones de hoy"; +"Scene.FollowedTags.Title" = "Etiquetas seguidas"; "Scene.Follower.Footer" = "No se muestran los seguidores de otros servidores."; "Scene.Follower.Title" = "seguidor"; "Scene.Following.Footer" = "No se muestran los seguidos de otros servidores."; @@ -241,9 +260,9 @@ pulsa en el enlace para confirmar tu cuenta."; "Scene.HomeTimeline.NavigationBarState.Published" = "¡Publicado!"; "Scene.HomeTimeline.NavigationBarState.Publishing" = "Publicación en curso..."; "Scene.HomeTimeline.Title" = "Inicio"; -"Scene.Login.ServerSearchField.Placeholder" = "Enter URL or search for your server"; -"Scene.Login.Subtitle" = "Log you in on the server you created your account on."; -"Scene.Login.Title" = "Welcome back"; +"Scene.Login.ServerSearchField.Placeholder" = "Introduzca la URL o busque su servidor"; +"Scene.Login.Subtitle" = "Inicie sesión en el servidor en el que creó su cuenta."; +"Scene.Login.Title" = "Bienvenido de nuevo"; "Scene.Notification.FollowRequest.Accept" = "Aceptar"; "Scene.Notification.FollowRequest.Accepted" = "Aceptado"; "Scene.Notification.FollowRequest.Reject" = "rechazar"; @@ -269,19 +288,20 @@ pulsa en el enlace para confirmar tu cuenta."; "Scene.Profile.Dashboard.Following" = "siguiendo"; "Scene.Profile.Dashboard.Posts" = "publicaciones"; "Scene.Profile.Fields.AddRow" = "Añadir Fila"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "Contenido"; "Scene.Profile.Fields.Placeholder.Label" = "Nombre para el campo"; -"Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %@"; -"Scene.Profile.Fields.Verified.Short" = "Verified on %@"; +"Scene.Profile.Fields.Verified.Long" = "La propiedad de este enlace fue verificada el %@"; +"Scene.Profile.Fields.Verified.Short" = "Verificado en %@"; "Scene.Profile.Header.FollowsYou" = "Te sigue"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Confirmar para bloquear a %@"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Bloquear cuenta"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Confirm to hide reblogs"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Hide Reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Confirmar para ocultar reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Ocultar reblogs"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Confirmar para silenciar %@"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Silenciar cuenta"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Confirm to show reblogs"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Show Reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Confirmar para mostrar reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Mostrar reblogs"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Confirmar para desbloquear a %@"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Desbloquear cuenta"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Confirmar para dejar de silenciar a %@"; @@ -405,11 +425,11 @@ pulsa en el enlace para confirmar tu cuenta."; "Scene.ServerPicker.EmptyState.BadNetwork" = "Algo ha ido mal al cargar los datos. Comprueba tu conexión a Internet."; "Scene.ServerPicker.EmptyState.FindingServers" = "Encontrando servidores disponibles..."; "Scene.ServerPicker.EmptyState.NoResults" = "Sin resultados"; -"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Buscar comunidades o introducir URL"; "Scene.ServerPicker.Label.Category" = "CATEGORÍA"; "Scene.ServerPicker.Label.Language" = "IDIOMA"; "Scene.ServerPicker.Label.Users" = "USUARIOS"; -"Scene.ServerPicker.Subtitle" = "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers."; +"Scene.ServerPicker.Subtitle" = "Escoge un servidor basado en tu región, intereses o un propósito general. Aún puedes chatear con cualquiera en Mastodon, independientemente de tus servidores."; "Scene.ServerPicker.Title" = "Elige un servidor, cualquier servidor."; "Scene.ServerRules.Button.Confirm" = "Acepto"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict index ca07b6b28..0a904fcfd 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict @@ -53,7 +53,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + Quedan %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -61,9 +61,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 carácter other - %ld characters + %ld caracteres plural.count.followed_by_and_mutual diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/eu.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/eu.lproj/Localizable.strings index e2985112e..882e05ec6 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/eu.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/eu.lproj/Localizable.strings @@ -22,6 +22,9 @@ Egiaztatu Interneteko konexioa."; "Common.Alerts.SignOut.Message" = "Ziur saioa amaitu nahi duzula?"; "Common.Alerts.SignOut.Title" = "Amaitu saioa"; "Common.Alerts.SignUpFailure.Title" = "Hutsegitea izen-ematean"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "Inkesta amaitu da"; "Common.Alerts.VoteFailure.Title" = "Hutsegitea botoa ematean"; "Common.Controls.Actions.Add" = "Gehitu"; @@ -31,6 +34,7 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Actions.Compose" = "Idatzi"; "Common.Controls.Actions.Confirm" = "Berretsi"; "Common.Controls.Actions.Continue" = "Jarraitu"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "Kopiatu argazkia"; "Common.Controls.Actions.Delete" = "Ezabatu"; "Common.Controls.Actions.Discard" = "Baztertu"; @@ -55,10 +59,12 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Actions.Share" = "Partekatu"; "Common.Controls.Actions.SharePost" = "Partekatu bidalketa"; "Common.Controls.Actions.ShareUser" = "Partekatu %@"; -"Common.Controls.Actions.SignIn" = "Log in"; -"Common.Controls.Actions.SignUp" = "Create account"; +"Common.Controls.Actions.SignIn" = "Hasi saioa"; +"Common.Controls.Actions.SignUp" = "Sortu kontua"; "Common.Controls.Actions.Skip" = "Saltatu"; "Common.Controls.Actions.TakePhoto" = "Atera argazkia"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "Saiatu berriro"; "Common.Controls.Actions.UnblockDomain" = "Desblokeatu %@"; "Common.Controls.Friendship.Block" = "Blokeatu"; @@ -68,13 +74,13 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Friendship.EditInfo" = "Editatu informazioa"; "Common.Controls.Friendship.Follow" = "Jarraitu"; "Common.Controls.Friendship.Following" = "Jarraitzen"; -"Common.Controls.Friendship.HideReblogs" = "Hide Reblogs"; +"Common.Controls.Friendship.HideReblogs" = "Ezkutatu bultzadak"; "Common.Controls.Friendship.Mute" = "Mututu"; "Common.Controls.Friendship.MuteUser" = "Mututu %@"; "Common.Controls.Friendship.Muted" = "Mutututa"; "Common.Controls.Friendship.Pending" = "Zain"; "Common.Controls.Friendship.Request" = "Eskaera"; -"Common.Controls.Friendship.ShowReblogs" = "Show Reblogs"; +"Common.Controls.Friendship.ShowReblogs" = "Ikusi bultzadak"; "Common.Controls.Friendship.Unblock" = "Desblokeatu"; "Common.Controls.Friendship.UnblockUser" = "Desblokeatu %@"; "Common.Controls.Friendship.Unmute" = "Desmututu"; @@ -100,6 +106,7 @@ 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.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "Erakutsi GIFa"; "Common.Controls.Status.Actions.ShowImage" = "Erakutsi irudia"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Erakutsi bideo-erreproduzigailua"; @@ -107,14 +114,16 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Status.Actions.Unfavorite" = "Kendu gogokoa"; "Common.Controls.Status.Actions.Unreblog" = "Desegin bultzada"; "Common.Controls.Status.ContentWarning" = "Edukiaren abisua"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "Ukitu edonon bistaratzeko"; -"Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; -"Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; -"Common.Controls.Status.MetaEntity.Mention" = "Show Profile: %@"; -"Common.Controls.Status.MetaEntity.Url" = "Link: %@"; +"Common.Controls.Status.MetaEntity.Email" = "E-posta helbidea: %@"; +"Common.Controls.Status.MetaEntity.Hashtag" = "Traolak: %@"; +"Common.Controls.Status.MetaEntity.Mention" = "Erakutsi Profila: %@"; +"Common.Controls.Status.MetaEntity.Url" = "Lotura: %@"; "Common.Controls.Status.Poll.Closed" = "Itxita"; "Common.Controls.Status.Poll.Vote" = "Bozkatu"; -"Common.Controls.Status.SensitiveContent" = "Sensitive Content"; +"Common.Controls.Status.SensitiveContent" = "Eduki hunkigarria"; "Common.Controls.Status.ShowPost" = "Erakutsi bidalketa"; "Common.Controls.Status.ShowUserProfile" = "Erakutsi erabiltzailearen profila"; "Common.Controls.Status.Tag.Email" = "Eposta"; @@ -124,6 +133,10 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Status.Tag.Mention" = "Aipatu"; "Common.Controls.Status.Tag.Url" = "URLa"; "Common.Controls.Status.TapToReveal" = "Sakatu erakusteko"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "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."; @@ -131,9 +144,9 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Nire jarraitzaileek soilik ikus dezakete bidalketa hau."; "Common.Controls.Status.Visibility.Unlisted" = "Edozeinek ikusi dezake bidalketa hau baina ez da denbora-lerro publikoan bistaratuko."; "Common.Controls.Tabs.Home" = "Hasiera"; -"Common.Controls.Tabs.Notification" = "Jakinarazpena"; +"Common.Controls.Tabs.Notifications" = "Notifications"; "Common.Controls.Tabs.Profile" = "Profila"; -"Common.Controls.Tabs.Search" = "Bilatu"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "Common.Controls.Timeline.Filtered" = "Iragazita"; "Common.Controls.Timeline.Header.BlockedWarning" = "Ezin duzu erabiltzaile honen profila ikusi desblokeatzen zaituen arte."; @@ -155,27 +168,27 @@ Zure profilak itxura hau du berarentzat."; "Scene.AccountList.AddAccount" = "Gehitu kontua"; "Scene.AccountList.DismissAccountSwitcher" = "Baztertu kontu-aldatzailea"; "Scene.AccountList.TabBarHint" = "Unean hautatutako profila: %@. Ukitu birritan, ondoren eduki sakatuta kontu-aldatzailea erakusteko"; -"Scene.Bookmark.Title" = "Bookmarks"; +"Scene.Bookmark.Title" = "Laster-markak"; "Scene.Compose.Accessibility.AppendAttachment" = "Gehitu eranskina"; "Scene.Compose.Accessibility.AppendPoll" = "Gehitu inkesta"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Emoji pertsonalizatuen hautatzailea"; "Scene.Compose.Accessibility.DisableContentWarning" = "Desgaitu edukiaren abisua"; "Scene.Compose.Accessibility.EnableContentWarning" = "Gaitu edukiaren abisua"; -"Scene.Compose.Accessibility.PostOptions" = "Post Options"; +"Scene.Compose.Accessibility.PostOptions" = "Bildalketaren aukerak"; "Scene.Compose.Accessibility.PostVisibilityMenu" = "Bidalketaren ikusgaitasunaren menua"; "Scene.Compose.Accessibility.PostingAs" = "Posting as %@"; "Scene.Compose.Accessibility.RemovePoll" = "Kendu inkesta"; "Scene.Compose.Attachment.AttachmentBroken" = "%@ hondatuta dago eta ezin da Mastodonera igo."; -"Scene.Compose.Attachment.AttachmentTooLarge" = "Attachment too large"; +"Scene.Compose.Attachment.AttachmentTooLarge" = "Eranskina handiegia da"; "Scene.Compose.Attachment.CanNotRecognizeThisMediaAttachment" = "Can not recognize this media attachment"; -"Scene.Compose.Attachment.CompressingState" = "Compressing..."; +"Scene.Compose.Attachment.CompressingState" = "Konprimatzen..."; "Scene.Compose.Attachment.DescriptionPhoto" = "Deskribatu argazkia ikusmen arazoak dituztenentzat..."; "Scene.Compose.Attachment.DescriptionVideo" = "Deskribatu bideoa ikusmen arazoak dituztenentzat..."; "Scene.Compose.Attachment.LoadFailed" = "Load Failed"; "Scene.Compose.Attachment.Photo" = "argazkia"; "Scene.Compose.Attachment.ServerProcessingState" = "Server Processing..."; -"Scene.Compose.Attachment.UploadFailed" = "Upload Failed"; +"Scene.Compose.Attachment.UploadFailed" = "Kargatzeak huts egin du"; "Scene.Compose.Attachment.Video" = "bideoa"; "Scene.Compose.AutoComplete.SpaceToAdd" = "Sakatu zuriunea gehitzeko"; "Scene.Compose.ComposeAction" = "Argitaratu"; @@ -197,7 +210,7 @@ Mastodonera igo."; "Scene.Compose.Poll.SevenDays" = "7 egun"; "Scene.Compose.Poll.SixHours" = "6 ordu"; "Scene.Compose.Poll.ThePollHasEmptyOption" = "The poll has empty option"; -"Scene.Compose.Poll.ThePollIsInvalid" = "The poll is invalid"; +"Scene.Compose.Poll.ThePollIsInvalid" = "Inkesta ez da balekoa"; "Scene.Compose.Poll.ThirtyMinutes" = "30 minutu"; "Scene.Compose.Poll.ThreeDays" = "3 egun"; "Scene.Compose.ReplyingToUser" = "%@(r)i erantzuten"; @@ -217,10 +230,10 @@ Mastodonera igo."; "Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Ireki eposta bezeroa"; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Egiaztatu zure sarrerako ontzia."; "Scene.ConfirmEmail.Subtitle" = "Sakatu epostaz bidali dizugun loturan zure kontua egiaztatzeko."; -"Scene.ConfirmEmail.TapTheLinkWeEmailedToYouToVerifyYourAccount" = "Tap the link we emailed to you to verify your account"; +"Scene.ConfirmEmail.TapTheLinkWeEmailedToYouToVerifyYourAccount" = "Sakatu epostaz bidali dizugun loturan zure kontua egiaztatzeko"; "Scene.ConfirmEmail.Title" = "Eta azkenik..."; -"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; -"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Intro" = "Hauek dira zure Mastodon txokoan beraien lekua hartzen ari diren argitalpenak."; +"Scene.Discovery.Tabs.Community" = "Komunitatea"; "Scene.Discovery.Tabs.ForYou" = "Zuretzat"; "Scene.Discovery.Tabs.Hashtags" = "Traolak"; "Scene.Discovery.Tabs.News" = "Albisteak"; @@ -229,12 +242,18 @@ Mastodonera igo."; "Scene.Familiarfollowers.Title" = "Followers you familiar"; "Scene.Favorite.Title" = "Zure gogokoak"; "Scene.FavoritedBy.Title" = "Favorited By"; +"Scene.FollowedTags.Actions.Follow" = "Follow"; +"Scene.FollowedTags.Actions.Unfollow" = "Unfollow"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "posts"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Followed Tags"; "Scene.Follower.Footer" = "Beste zerbitzarietako jarraitzaileak ez dira bistaratzen."; -"Scene.Follower.Title" = "follower"; +"Scene.Follower.Title" = "jarraitzaile"; "Scene.Following.Footer" = "Beste zerbitzarietan jarraitutakoak ez dira bistaratzen."; -"Scene.Following.Title" = "following"; +"Scene.Following.Title" = "jarraitzen"; "Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; -"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo botoia"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Ikusi bidal. berriak"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Konexio gabe"; "Scene.HomeTimeline.NavigationBarState.Published" = "Argitaratua!"; @@ -242,11 +261,11 @@ Mastodonera igo."; "Scene.HomeTimeline.Title" = "Hasiera"; "Scene.Login.ServerSearchField.Placeholder" = "Enter URL or search for your server"; "Scene.Login.Subtitle" = "Log you in on the server you created your account on."; -"Scene.Login.Title" = "Welcome back"; -"Scene.Notification.FollowRequest.Accept" = "Accept"; -"Scene.Notification.FollowRequest.Accepted" = "Accepted"; -"Scene.Notification.FollowRequest.Reject" = "reject"; -"Scene.Notification.FollowRequest.Rejected" = "Rejected"; +"Scene.Login.Title" = "Ongi etorri berriro ere"; +"Scene.Notification.FollowRequest.Accept" = "Onartu"; +"Scene.Notification.FollowRequest.Accepted" = "Onartuta"; +"Scene.Notification.FollowRequest.Reject" = "ukatu"; +"Scene.Notification.FollowRequest.Rejected" = "Ukatua"; "Scene.Notification.Keyobard.ShowEverything" = "Erakutsi guztia"; "Scene.Notification.Keyobard.ShowMentions" = "Erakutsi aipamenak"; "Scene.Notification.NotificationDescription.FavoritedYourPost" = "(e)k zure bidalketa gogoko du"; @@ -268,19 +287,20 @@ Mastodonera igo."; "Scene.Profile.Dashboard.Following" = "jarraitzen"; "Scene.Profile.Dashboard.Posts" = "bidalketa"; "Scene.Profile.Fields.AddRow" = "Gehitu errenkada"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "Edukia"; "Scene.Profile.Fields.Placeholder.Label" = "Etiketa"; -"Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %@"; +"Scene.Profile.Fields.Verified.Long" = "Esteka honen jabetzaren egiaztaketa data: %@"; "Scene.Profile.Fields.Verified.Short" = "Verified on %@"; -"Scene.Profile.Header.FollowsYou" = "Follows You"; +"Scene.Profile.Header.FollowsYou" = "Jarraitzen zaitu"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Berretsi %@ blokeatzea"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Blokeatu kontua"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Confirm to hide reblogs"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Hide Reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Berretsi birbidalketak ezkutatzea"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Ezkutatu bultzadak"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Berretsi %@ mututzea"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Mututu kontua"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Confirm to show reblogs"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Show Reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Berretsi birbidalketak ikustea"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Ikusi bultzadak"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Berretsi %@ desblokeatzea"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Desblokeatu kontua"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Berretsi %@ desmututzea"; @@ -323,7 +343,7 @@ Mastodonera igo."; "Scene.Register.Input.Password.Require" = "Zure pasahitzak izan behar ditu gutxienez:"; "Scene.Register.Input.Username.DuplicatePrompt" = "Erabiltzaile-izen hau hartuta dago."; "Scene.Register.Input.Username.Placeholder" = "erabiltzaile-izena"; -"Scene.Register.LetsGetYouSetUpOnDomain" = "Let’s get you set up on %@"; +"Scene.Register.LetsGetYouSetUpOnDomain" = "%@ zerbitzariko kontua prestatuko dizugu"; "Scene.Register.Title" = "Hitz egin iezaguzu zuri buruz."; "Scene.Report.Content1" = "Salaketan beste bidalketarik gehitu nahi duzu?"; "Scene.Report.Content2" = "Moderatzaileek besterik jakin behar dute salaketa honi buruz?"; @@ -333,38 +353,38 @@ Mastodonera igo."; "Scene.Report.SkipToSend" = "Bidali iruzkinik gabe"; "Scene.Report.Step1" = "1. urratsa 2tik"; "Scene.Report.Step2" = "2. urratsa 2tik"; -"Scene.Report.StepFinal.BlockUser" = "Block %@"; -"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; -"Scene.Report.StepFinal.MuteUser" = "Mute %@"; -"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; -"Scene.Report.StepFinal.Unfollow" = "Unfollow"; -"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.BlockUser" = "Blokeatu %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Ez duzu hau ikusi nahi?"; +"Scene.Report.StepFinal.MuteUser" = "Mututu %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "Ezin izango dituzte zure bidalketak jarraitu edo ikusi, baina blokeatuta dauden ikusi ahal izango dute."; +"Scene.Report.StepFinal.Unfollow" = "Utzi jarraitzeari"; +"Scene.Report.StepFinal.UnfollowUser" = "%@ jarraitzeari utzi"; "Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; -"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; -"Scene.Report.StepFinal.WhileWeReviewThisYouCanTakeActionAgainstUser" = "While we review this, you can take action against %@"; -"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; -"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; -"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; -"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; -"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; -"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; -"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; -"Scene.Report.StepOne.ItsSpam" = "It’s spam"; -"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; -"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; -"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; -"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; -"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; -"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; -"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; -"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; -"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; -"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; -"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "Mastodonen gustuko ez duzun zerbait ikusten duzunean, zure esperientziatik atera dezakezu pertsona hori."; +"Scene.Report.StepFinal.WhileWeReviewThisYouCanTakeActionAgainstUser" = "Hau berrikusten dugun bitartean, %@ erabiltzailearen aurkako neurriak hartu ditzakezu"; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "Ez dituzu bere bidalketa eta birbidalketak zure hasierako jarioan ikusiko. Ez dute jakingo isilarazi dituztenik."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Beste zerbait jakin beharko genuke?"; +"Scene.Report.StepFour.Step4Of4" = "4. urratsa 4tik"; +"Scene.Report.StepOne.IDontLikeIt" = "Ez dut gustukoa"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "Ikusi nahi ez dudan zerbait da"; +"Scene.Report.StepOne.ItViolatesServerRules" = "Zerbitzariaren arauak hausten ditu"; +"Scene.Report.StepOne.ItsSomethingElse" = "Beste zerbait da"; +"Scene.Report.StepOne.ItsSpam" = "Spama da"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Esteka maltzurrak, gezurrezko elkarrekintzak edo erantzun errepikakorrak"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Aukeratu egokiena"; +"Scene.Report.StepOne.Step1Of4" = "1. urratsa 4tik"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "Arazoa ezin da beste kategorietan sailkatu"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "Zer du txarra kontu honek?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "Zer du txarra argitalpen honek?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "Zer du txarra %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "Arau zehatzak urratzen dituela badakizu"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Salaketa hau babesten duen bidalketarik badago?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Hautatu dagozkion guztiak"; +"Scene.Report.StepThree.Step3Of4" = "3. urratsa 4tik"; "Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; -"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; -"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; -"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Hautatu dagozkion guztiak"; +"Scene.Report.StepTwo.Step2Of4" = "2. urratsa 4tik"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Ze arau hautsi ditu?"; "Scene.Report.TextPlaceholder" = "Idatzi edo itsatsi iruzkin gehigarriak"; "Scene.Report.Title" = "Salatu %@"; "Scene.Report.TitleReport" = "Salatu"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/eu.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/eu.lproj/Localizable.stringsdict index 057ca4010..404deebd3 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/eu.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/eu.lproj/Localizable.stringsdict @@ -63,13 +63,13 @@ one 1 character other - %ld characters + %ld karaktere plural.count.followed_by_and_mutual NSStringLocalizedFormatKey - %#@names@%#@count_mutual@ + %#@names@: "%#@count_mutual@ names one diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/fi.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/fi.lproj/Localizable.strings index 7902fb6eb..de4bf3101 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/fi.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/fi.lproj/Localizable.strings @@ -22,6 +22,9 @@ Tarkista internet-yhteytesi."; "Common.Alerts.SignOut.Message" = "Haluatko varmasti kirjautua ulos?"; "Common.Alerts.SignOut.Title" = "Kirjaudu ulos"; "Common.Alerts.SignUpFailure.Title" = "Rekisteröinti epäonnistui"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "Kysely on päättynyt"; "Common.Alerts.VoteFailure.Title" = "Vote Failure"; "Common.Controls.Actions.Add" = "Lisää"; @@ -31,6 +34,7 @@ Tarkista internet-yhteytesi."; "Common.Controls.Actions.Compose" = "Koosta"; "Common.Controls.Actions.Confirm" = "Vahvista"; "Common.Controls.Actions.Continue" = "Jatka"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "Kopioi kuva"; "Common.Controls.Actions.Delete" = "Poista"; "Common.Controls.Actions.Discard" = "Hylkää"; @@ -59,6 +63,8 @@ Tarkista internet-yhteytesi."; "Common.Controls.Actions.SignUp" = "Create account"; "Common.Controls.Actions.Skip" = "Ohita"; "Common.Controls.Actions.TakePhoto" = "Ota kuva"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "Yritä uudelleen"; "Common.Controls.Actions.UnblockDomain" = "Poista esto %@"; "Common.Controls.Friendship.Block" = "Estä"; @@ -100,6 +106,7 @@ 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.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "Show GIF"; "Common.Controls.Status.Actions.ShowImage" = "Show image"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; @@ -107,6 +114,8 @@ Tarkista internet-yhteytesi."; "Common.Controls.Status.Actions.Unfavorite" = "Unfavorite"; "Common.Controls.Status.Actions.Unreblog" = "Peru edelleen jako"; "Common.Controls.Status.ContentWarning" = "Sisältövaroitus"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "Napauta mistä tahansa paljastaaksesi"; "Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; @@ -124,6 +133,10 @@ Tarkista internet-yhteytesi."; "Common.Controls.Status.Tag.Mention" = "Mention"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ jakoi edelleen"; "Common.Controls.Status.UserRepliedTo" = "Vastasi %@:lle"; "Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; @@ -131,9 +144,9 @@ Tarkista internet-yhteytesi."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Only my followers can see this post."; "Common.Controls.Status.Visibility.Unlisted" = "Everyone can see this post but not display in the public timeline."; "Common.Controls.Tabs.Home" = "Koti"; -"Common.Controls.Tabs.Notification" = "Ilmoitus"; +"Common.Controls.Tabs.Notifications" = "Notifications"; "Common.Controls.Tabs.Profile" = "Profiili"; -"Common.Controls.Tabs.Search" = "Haku"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "Common.Controls.Timeline.Filtered" = "Suodatettu"; "Common.Controls.Timeline.Header.BlockedWarning" = "Et voi tarkastella tämän tilin profiilia ennen kuin hän poistaa eston."; @@ -229,6 +242,12 @@ uploaded to Mastodon."; "Scene.Familiarfollowers.Title" = "Followers you familiar"; "Scene.Favorite.Title" = "Omat suosikit"; "Scene.FavoritedBy.Title" = "Favorited By"; +"Scene.FollowedTags.Actions.Follow" = "Follow"; +"Scene.FollowedTags.Actions.Unfollow" = "Unfollow"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "posts"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Followed Tags"; "Scene.Follower.Footer" = "Seuraajia muilta palvelimilta ei näytetä."; "Scene.Follower.Title" = "follower"; "Scene.Following.Footer" = "Seurauksia muilta palvelimilta ei näytetä."; @@ -268,6 +287,7 @@ uploaded to Mastodon."; "Scene.Profile.Dashboard.Following" = "seurataan"; "Scene.Profile.Dashboard.Posts" = "julkaisut"; "Scene.Profile.Fields.AddRow" = "Lisää rivi"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "Sisältö"; "Scene.Profile.Fields.Placeholder.Label" = "Nimi"; "Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings index f393adec1..0bc619b34 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings @@ -22,6 +22,9 @@ Veuillez vérifier votre accès à Internet."; "Common.Alerts.SignOut.Message" = "Voulez-vous vraiment vous déconnecter ?"; "Common.Alerts.SignOut.Title" = "Se déconnecter"; "Common.Alerts.SignUpFailure.Title" = "Échec de l'inscription"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "La traduction a échoué. Peut-être que l'administrateur n'a pas activé les traductions sur ce serveur ou que ce serveur utilise une ancienne version de Mastodon où les traductions ne sont pas encore prises en charge."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "Le sondage est terminé"; "Common.Alerts.VoteFailure.Title" = "Échec du vote"; "Common.Controls.Actions.Add" = "Ajouter"; @@ -31,6 +34,7 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Actions.Compose" = "Rédiger"; "Common.Controls.Actions.Confirm" = "Confirmer"; "Common.Controls.Actions.Continue" = "Continuer"; +"Common.Controls.Actions.Copy" = "Copier"; "Common.Controls.Actions.CopyPhoto" = "Copier la photo"; "Common.Controls.Actions.Delete" = "Supprimer"; "Common.Controls.Actions.Discard" = "Abandonner"; @@ -59,6 +63,8 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Actions.SignUp" = "Créer un compte"; "Common.Controls.Actions.Skip" = "Passer"; "Common.Controls.Actions.TakePhoto" = "Prendre une photo"; +"Common.Controls.Actions.TranslatePost.Title" = "Traduit depuis %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Inconnu"; "Common.Controls.Actions.TryAgain" = "Réessayer"; "Common.Controls.Actions.UnblockDomain" = "Débloquer %@"; "Common.Controls.Friendship.Block" = "Bloquer"; @@ -100,6 +106,7 @@ 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.ShareLinkInPost" = "Partager le lien dans le message"; "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"; @@ -107,6 +114,8 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Status.Actions.Unfavorite" = "Retirer des favoris"; "Common.Controls.Status.Actions.Unreblog" = "Annuler le reblog"; "Common.Controls.Status.ContentWarning" = "Avertissement de contenu"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Charger l'intégration"; "Common.Controls.Status.MediaContentWarning" = "Tapotez n’importe où pour révéler la publication"; "Common.Controls.Status.MetaEntity.Email" = "Adresse e-mail : %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag : %@"; @@ -124,6 +133,10 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Status.Tag.Mention" = "Mention"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Appuyer pour afficher"; +"Common.Controls.Status.Translation.ShowOriginal" = "Afficher l’original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Inconnu"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "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."; @@ -131,9 +144,9 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Seul·e·s mes abonné·e·s peuvent voir ce message."; "Common.Controls.Status.Visibility.Unlisted" = "Tout le monde peut voir ce message mais ne sera pas affiché sur le fil public."; "Common.Controls.Tabs.Home" = "Accueil"; -"Common.Controls.Tabs.Notification" = "Notification"; +"Common.Controls.Tabs.Notifications" = "Notifications"; "Common.Controls.Tabs.Profile" = "Profil"; -"Common.Controls.Tabs.Search" = "Rechercher"; +"Common.Controls.Tabs.SearchAndExplore" = "Rechercher et explorer"; "Common.Controls.Timeline.Filtered" = "Filtré"; "Common.Controls.Timeline.Header.BlockedWarning" = "Vous ne pouvez pas voir le profil de cet utilisateur tant qu'il ne vous aura pas débloqué."; @@ -229,6 +242,12 @@ téléversé sur Mastodon."; "Scene.Familiarfollowers.Title" = "Abonné·e·s que vous connaissez"; "Scene.Favorite.Title" = "Vos favoris"; "Scene.FavoritedBy.Title" = "Favoris par"; +"Scene.FollowedTags.Actions.Follow" = "Suivre"; +"Scene.FollowedTags.Actions.Unfollow" = "Ne plus suivre"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "messages"; +"Scene.FollowedTags.Header.PostsToday" = "messages aujourd'hui"; +"Scene.FollowedTags.Title" = "Tags suivis"; "Scene.Follower.Footer" = "Les abonné·e·s issus des autres serveurs ne sont pas affiché·e·s."; "Scene.Follower.Title" = "abonné·e"; "Scene.Following.Footer" = "Les abonnés issus des autres serveurs ne sont pas affichés."; @@ -268,6 +287,7 @@ téléversé sur Mastodon."; "Scene.Profile.Dashboard.Following" = "abonnements"; "Scene.Profile.Dashboard.Posts" = "publications"; "Scene.Profile.Fields.AddRow" = "Ajouter une rangée"; +"Scene.Profile.Fields.Joined" = "Ici depuis"; "Scene.Profile.Fields.Placeholder.Content" = "Contenu"; "Scene.Profile.Fields.Placeholder.Label" = "Étiquette"; "Scene.Profile.Fields.Verified.Long" = "La propriété de ce lien a été vérifiée le %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gd.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gd.lproj/Localizable.strings index 6ccf6cf15..e37be3344 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gd.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gd.lproj/Localizable.strings @@ -22,6 +22,9 @@ Thoir sùil air a’ cheangal agad ris an eadar-lìon."; "Common.Alerts.SignOut.Message" = "A bheil thu cinnteach gu bheil thu airson clàradh a-mach?"; "Common.Alerts.SignOut.Title" = "Clàraich a-mach"; "Common.Alerts.SignUpFailure.Title" = "Dh’fhàillig leis a’ chlàradh"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "Thàinig an cunntas-bheachd gu crìoch"; "Common.Alerts.VoteFailure.Title" = "Dh’fhàillig leis a’ bhòt"; "Common.Controls.Actions.Add" = "Cuir ris"; @@ -31,6 +34,7 @@ Thoir sùil air a’ cheangal agad ris an eadar-lìon."; "Common.Controls.Actions.Compose" = "Sgrìobh"; "Common.Controls.Actions.Confirm" = "Dearbh"; "Common.Controls.Actions.Continue" = "Lean air adhart"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "Dèan lethbhreac dhen dealbh"; "Common.Controls.Actions.Delete" = "Sguab às"; "Common.Controls.Actions.Discard" = "Tilg air falbh"; @@ -59,6 +63,8 @@ Thoir sùil air a’ cheangal agad ris an eadar-lìon."; "Common.Controls.Actions.SignUp" = "Cruthaich cunntas"; "Common.Controls.Actions.Skip" = "Leum thairis air"; "Common.Controls.Actions.TakePhoto" = "Tog dealbh"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "Feuch ris a-rithist"; "Common.Controls.Actions.UnblockDomain" = "Dì-bhac %@"; "Common.Controls.Friendship.Block" = "Bac"; @@ -100,6 +106,7 @@ 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.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "Seall an GIF"; "Common.Controls.Status.Actions.ShowImage" = "Seall an dealbh"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Seall cluicheadair video"; @@ -107,6 +114,8 @@ Thoir sùil air a’ cheangal agad ris an eadar-lìon."; "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"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "Thoir gnogag àite sam bith gus a nochdadh"; "Common.Controls.Status.MetaEntity.Email" = "Seòladh puist-d: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Taga hais: %@"; @@ -124,6 +133,10 @@ Thoir sùil air a’ cheangal agad ris an eadar-lìon."; "Common.Controls.Status.Tag.Mention" = "Iomradh"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Thoir gnogag gus a nochdadh"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "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."; @@ -131,9 +144,9 @@ Thoir sùil air a’ cheangal agad ris an eadar-lìon."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Chan fhaic ach an luchd-leantainn agam am post seo."; "Common.Controls.Status.Visibility.Unlisted" = "Chì a h-uile duine am post seo ach cha nochd e air an loidhne-ama phoblach."; "Common.Controls.Tabs.Home" = "Dachaigh"; -"Common.Controls.Tabs.Notification" = "Brath"; +"Common.Controls.Tabs.Notifications" = "Notifications"; "Common.Controls.Tabs.Profile" = "Pròifil"; -"Common.Controls.Tabs.Search" = "Lorg"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "Common.Controls.Timeline.Filtered" = "Criathraichte"; "Common.Controls.Timeline.Header.BlockedWarning" = "Chan fhaic thu pròifil a’ chleachdaiche seo mus dì-bhac iad thu."; @@ -229,6 +242,12 @@ a luchdadh suas gu Mastodon."; "Scene.Familiarfollowers.Title" = "Luchd-leantainn aithnichte"; "Scene.Favorite.Title" = "Na h-annsachdan agad"; "Scene.FavoritedBy.Title" = "’Na annsachd aig"; +"Scene.FollowedTags.Actions.Follow" = "Follow"; +"Scene.FollowedTags.Actions.Unfollow" = "Unfollow"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "posts"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Followed Tags"; "Scene.Follower.Footer" = "Cha dèid luchd-leantainn o fhrithealaichean eile a shealltainn."; "Scene.Follower.Title" = "neach-leantainn"; "Scene.Following.Footer" = "Cha dèid cò a leanas tu air frithealaichean eile a shealltainn."; @@ -268,6 +287,7 @@ a luchdadh suas gu Mastodon."; "Scene.Profile.Dashboard.Following" = "a’ leantainn"; "Scene.Profile.Dashboard.Posts" = "postaichean"; "Scene.Profile.Fields.AddRow" = "Cuir ràgh ris"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "Susbaint"; "Scene.Profile.Fields.Placeholder.Label" = "Leubail"; "Scene.Profile.Fields.Verified.Long" = "Chaidh dearbhadh cò leis a tha an ceangal seo %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings index f9e1c6589..35a465661 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings @@ -22,6 +22,9 @@ Comproba a conexión a internet."; "Common.Alerts.SignOut.Message" = "Tes a certeza de queres pechar a sesión?"; "Common.Alerts.SignOut.Title" = "Pechar sesión"; "Common.Alerts.SignUpFailure.Title" = "Fallou o rexistro"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Fallou a tradución. É posible que a administración non activase a tradución neste servidor ou que o servidor teña unha versión antiga de Mastodon que non ten soporte para a tradución."; +"Common.Alerts.TranslationFailed.Title" = "Nota"; "Common.Alerts.VoteFailure.PollEnded" = "A enquisa rematou"; "Common.Alerts.VoteFailure.Title" = "Fallou a votación"; "Common.Controls.Actions.Add" = "Engadir"; @@ -31,6 +34,7 @@ Comproba a conexión a internet."; "Common.Controls.Actions.Compose" = "Escribir"; "Common.Controls.Actions.Confirm" = "Confirmar"; "Common.Controls.Actions.Continue" = "Continuar"; +"Common.Controls.Actions.Copy" = "Copiar"; "Common.Controls.Actions.CopyPhoto" = "Copiar foto"; "Common.Controls.Actions.Delete" = "Eliminar"; "Common.Controls.Actions.Discard" = "Descartar"; @@ -59,6 +63,8 @@ Comproba a conexión a internet."; "Common.Controls.Actions.SignUp" = "Crear conta"; "Common.Controls.Actions.Skip" = "Omitir"; "Common.Controls.Actions.TakePhoto" = "Facer foto"; +"Common.Controls.Actions.TranslatePost.Title" = "Traducido do %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Descoñecido"; "Common.Controls.Actions.TryAgain" = "Intentar de novo"; "Common.Controls.Actions.UnblockDomain" = "Desbloquear a %@"; "Common.Controls.Friendship.Block" = "Bloquear"; @@ -100,6 +106,7 @@ Comproba a conexión a internet."; "Common.Controls.Status.Actions.Menu" = "Menú"; "Common.Controls.Status.Actions.Reblog" = "Promover"; "Common.Controls.Status.Actions.Reply" = "Responder"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Compartir Ligazón na Publicación"; "Common.Controls.Status.Actions.ShowGif" = "Mostrar GIF"; "Common.Controls.Status.Actions.ShowImage" = "Mostrar a imaxe"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Mostrar reprodutor de vídeo"; @@ -107,6 +114,8 @@ Comproba a conexión a internet."; "Common.Controls.Status.Actions.Unfavorite" = "Eliminar dos favoritos"; "Common.Controls.Status.Actions.Unreblog" = "Retirar promoción"; "Common.Controls.Status.ContentWarning" = "Aviso sobre o contido"; +"Common.Controls.Status.LinkViaUser" = "%@ vía %@"; +"Common.Controls.Status.LoadEmbed" = "Cargar o contido"; "Common.Controls.Status.MediaContentWarning" = "Toca nalgures para mostrar"; "Common.Controls.Status.MetaEntity.Email" = "Enderezo de email: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Cancelo: %@"; @@ -124,6 +133,10 @@ Comproba a conexión a internet."; "Common.Controls.Status.Tag.Mention" = "Mención"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Toca para mostrar"; +"Common.Controls.Status.Translation.ShowOriginal" = "Mostrar o orixinal"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Descoñecido"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ promoveu"; "Common.Controls.Status.UserRepliedTo" = "Respondeu a %@"; "Common.Controls.Status.Visibility.Direct" = "Só a usuaria mencionada pode ver a publicación."; @@ -131,9 +144,9 @@ Comproba a conexión a internet."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Só as miñas seguidoras poden ver esta publicación."; "Common.Controls.Status.Visibility.Unlisted" = "A publicación é visible para calquera pero non aparece na cronoloxía pública."; "Common.Controls.Tabs.Home" = "Inicio"; -"Common.Controls.Tabs.Notification" = "Notificación"; +"Common.Controls.Tabs.Notifications" = "Notificacións"; "Common.Controls.Tabs.Profile" = "Perfil"; -"Common.Controls.Tabs.Search" = "Busca"; +"Common.Controls.Tabs.SearchAndExplore" = "Buscar e Explorar"; "Common.Controls.Timeline.Filtered" = "Filtrado"; "Common.Controls.Timeline.Header.BlockedWarning" = "Non podes ver o perfil desta usuaria ata que te desbloquee."; @@ -229,6 +242,12 @@ ser subido a Mastodon."; "Scene.Familiarfollowers.Title" = "Seguimentos próximos"; "Scene.Favorite.Title" = "Publicacións Favoritas"; "Scene.FavoritedBy.Title" = "Favorecido por"; +"Scene.FollowedTags.Actions.Follow" = "Seguir"; +"Scene.FollowedTags.Actions.Unfollow" = "Deixar de seguir"; +"Scene.FollowedTags.Header.Participants" = "participantes"; +"Scene.FollowedTags.Header.Posts" = "publicacións"; +"Scene.FollowedTags.Header.PostsToday" = "publicacións de hoxe"; +"Scene.FollowedTags.Title" = "Cancelos seguidos"; "Scene.Follower.Footer" = "Non se mostran seguidoras desde outros servidores."; "Scene.Follower.Title" = "seguidora"; "Scene.Following.Footer" = "Non se mostran os seguimentos desde outros servidores."; @@ -268,6 +287,7 @@ ser subido a Mastodon."; "Scene.Profile.Dashboard.Following" = "seguindo"; "Scene.Profile.Dashboard.Posts" = "publicacións"; "Scene.Profile.Fields.AddRow" = "Engadir fila"; +"Scene.Profile.Fields.Joined" = "Uniuse"; "Scene.Profile.Fields.Placeholder.Content" = "Contido"; "Scene.Profile.Fields.Placeholder.Label" = "Etiqueta"; "Scene.Profile.Fields.Verified.Long" = "A propiedade desta ligazón foi verificada o %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings index fab67c38d..96af84e22 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings @@ -22,6 +22,9 @@ Per favore verifica la tua connessione internet."; "Common.Alerts.SignOut.Message" = "Vuoi davvero scollegarti?"; "Common.Alerts.SignOut.Title" = "Esci"; "Common.Alerts.SignUpFailure.Title" = "Iscrizione fallita"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Traduzione fallita. Forse l'amministratore non ha abilitato le traduzioni su questo server o questo server sta eseguendo una versione precedente di Mastodon in cui le traduzioni non sono ancora supportate."; +"Common.Alerts.TranslationFailed.Title" = "Nota"; "Common.Alerts.VoteFailure.PollEnded" = "Il sondaggio è terminato"; "Common.Alerts.VoteFailure.Title" = "Voto fallito"; "Common.Controls.Actions.Add" = "Aggiungi"; @@ -31,6 +34,7 @@ Per favore verifica la tua connessione internet."; "Common.Controls.Actions.Compose" = "Scrivi"; "Common.Controls.Actions.Confirm" = "Conferma"; "Common.Controls.Actions.Continue" = "Continua"; +"Common.Controls.Actions.Copy" = "Copia"; "Common.Controls.Actions.CopyPhoto" = "Copia foto"; "Common.Controls.Actions.Delete" = "Elimina"; "Common.Controls.Actions.Discard" = "Abbandona"; @@ -59,6 +63,8 @@ Per favore verifica la tua connessione internet."; "Common.Controls.Actions.SignUp" = "Crea un account"; "Common.Controls.Actions.Skip" = "Salta"; "Common.Controls.Actions.TakePhoto" = "Scatta foto"; +"Common.Controls.Actions.TranslatePost.Title" = "Traduci da %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Sconosciuto"; "Common.Controls.Actions.TryAgain" = "Riprova"; "Common.Controls.Actions.UnblockDomain" = "Sblocca %@"; "Common.Controls.Friendship.Block" = "Blocca"; @@ -100,6 +106,7 @@ Per favore verifica la tua connessione internet."; "Common.Controls.Status.Actions.Menu" = "Menù"; "Common.Controls.Status.Actions.Reblog" = "Condivisione"; "Common.Controls.Status.Actions.Reply" = "Rispondi"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Condividi il collegamento nel post"; "Common.Controls.Status.Actions.ShowGif" = "Mostra GIF"; "Common.Controls.Status.Actions.ShowImage" = "Mostra immagine"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Mostra lettore video"; @@ -107,6 +114,8 @@ Per favore verifica la tua connessione internet."; "Common.Controls.Status.Actions.Unfavorite" = "Non preferito"; "Common.Controls.Status.Actions.Unreblog" = "Annulla condivisione"; "Common.Controls.Status.ContentWarning" = "Avviso sul contenuto"; +"Common.Controls.Status.LinkViaUser" = "%@ tramite %@"; +"Common.Controls.Status.LoadEmbed" = "Carica Incorpora"; "Common.Controls.Status.MediaContentWarning" = "Tocca ovunque per rivelare"; "Common.Controls.Status.MetaEntity.Email" = "Indirizzo email: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; @@ -119,11 +128,15 @@ Per favore verifica la tua connessione internet."; "Common.Controls.Status.ShowUserProfile" = "Mostra il profilo dell'utente"; "Common.Controls.Status.Tag.Email" = "Email"; "Common.Controls.Status.Tag.Emoji" = "Emoji"; -"Common.Controls.Status.Tag.Hashtag" = "Etichetta"; +"Common.Controls.Status.Tag.Hashtag" = "Hashtag"; "Common.Controls.Status.Tag.Link" = "Collegamento"; "Common.Controls.Status.Tag.Mention" = "Menzione"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Tocca per rivelare"; +"Common.Controls.Status.Translation.ShowOriginal" = "Mostra l'originale"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Sconosciuto"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ ha condiviso"; "Common.Controls.Status.UserRepliedTo" = "Risposta a %@"; "Common.Controls.Status.Visibility.Direct" = "Solo l'utente menzionato può vedere questo post."; @@ -131,9 +144,9 @@ Per favore verifica la tua connessione internet."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Solo i miei seguaci possono vedere questo post."; "Common.Controls.Status.Visibility.Unlisted" = "Tutti possono vedere questo post ma non mostrare nella cronologia pubblica."; "Common.Controls.Tabs.Home" = "Inizio"; -"Common.Controls.Tabs.Notification" = "Notifiche"; +"Common.Controls.Tabs.Notifications" = "Notifiche"; "Common.Controls.Tabs.Profile" = "Profilo"; -"Common.Controls.Tabs.Search" = "Cerca"; +"Common.Controls.Tabs.SearchAndExplore" = "Cerca ed Esplora"; "Common.Controls.Timeline.Filtered" = "Filtrato"; "Common.Controls.Timeline.Header.BlockedWarning" = "Non puoi visualizzare il profilo di questo utente fino a quando non ti sbloccano."; @@ -229,6 +242,12 @@ caricato su Mastodon."; "Scene.Familiarfollowers.Title" = "Seguaci che conosci"; "Scene.Favorite.Title" = "I tuoi preferiti"; "Scene.FavoritedBy.Title" = "Preferito Da"; +"Scene.FollowedTags.Actions.Follow" = "Segui"; +"Scene.FollowedTags.Actions.Unfollow" = "Smetti di seguire"; +"Scene.FollowedTags.Header.Participants" = "partecipanti"; +"Scene.FollowedTags.Header.Posts" = "post"; +"Scene.FollowedTags.Header.PostsToday" = "post di oggi"; +"Scene.FollowedTags.Title" = "Etichette seguite"; "Scene.Follower.Footer" = "I seguaci da altri server non vengono visualizzati."; "Scene.Follower.Title" = "seguace"; "Scene.Following.Footer" = "I follow da altri server non vengono visualizzati."; @@ -268,6 +287,7 @@ caricato su Mastodon."; "Scene.Profile.Dashboard.Following" = "seguendo"; "Scene.Profile.Dashboard.Posts" = "post"; "Scene.Profile.Fields.AddRow" = "Aggiungi riga"; +"Scene.Profile.Fields.Joined" = "Profilo iscritto"; "Scene.Profile.Fields.Placeholder.Content" = "Contenuto"; "Scene.Profile.Fields.Placeholder.Label" = "Etichetta"; "Scene.Profile.Fields.Verified.Long" = "La proprietà di questo collegamento è stata verificata il %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings index 01701dfc2..3d32c96d1 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings @@ -22,6 +22,9 @@ "Common.Alerts.SignOut.Message" = "本当にサインアウトしますか?"; "Common.Alerts.SignOut.Title" = "サインアウト"; "Common.Alerts.SignUpFailure.Title" = "サインアップに失敗しました"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "投票は終了しました"; "Common.Alerts.VoteFailure.Title" = "投票の失敗"; "Common.Controls.Actions.Add" = "追加"; @@ -31,6 +34,7 @@ "Common.Controls.Actions.Compose" = "新規作成"; "Common.Controls.Actions.Confirm" = "確認"; "Common.Controls.Actions.Continue" = "続ける"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "写真をコピー"; "Common.Controls.Actions.Delete" = "削除"; "Common.Controls.Actions.Discard" = "破棄"; @@ -49,16 +53,18 @@ "Common.Controls.Actions.Reply" = "返信"; "Common.Controls.Actions.ReportUser" = "%@を通報"; "Common.Controls.Actions.Save" = "保存"; -"Common.Controls.Actions.SavePhoto" = "写真を撮る"; +"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.SignIn" = "Log in"; -"Common.Controls.Actions.SignUp" = "Create account"; +"Common.Controls.Actions.SignIn" = "ログイン"; +"Common.Controls.Actions.SignUp" = "アカウント作成"; "Common.Controls.Actions.Skip" = "スキップ"; "Common.Controls.Actions.TakePhoto" = "写真を撮る"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "再実行"; "Common.Controls.Actions.UnblockDomain" = "%@のブロックを解除"; "Common.Controls.Friendship.Block" = "ブロック"; @@ -68,13 +74,13 @@ "Common.Controls.Friendship.EditInfo" = "編集"; "Common.Controls.Friendship.Follow" = "フォロー"; "Common.Controls.Friendship.Following" = "フォロー中"; -"Common.Controls.Friendship.HideReblogs" = "Hide Reblogs"; +"Common.Controls.Friendship.HideReblogs" = "ブーストを非表示"; "Common.Controls.Friendship.Mute" = "ミュート"; "Common.Controls.Friendship.MuteUser" = "%@をミュート"; "Common.Controls.Friendship.Muted" = "ミュート済み"; "Common.Controls.Friendship.Pending" = "保留"; "Common.Controls.Friendship.Request" = "リクエスト"; -"Common.Controls.Friendship.ShowReblogs" = "Show Reblogs"; +"Common.Controls.Friendship.ShowReblogs" = "ブーストを表示"; "Common.Controls.Friendship.Unblock" = "ブロックを解除"; "Common.Controls.Friendship.UnblockUser" = "%@のブロックを解除"; "Common.Controls.Friendship.Unmute" = "ミュートを解除"; @@ -100,6 +106,7 @@ "Common.Controls.Status.Actions.Menu" = "メニュー"; "Common.Controls.Status.Actions.Reblog" = "ブースト"; "Common.Controls.Status.Actions.Reply" = "返信"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "GIFを表示"; "Common.Controls.Status.Actions.ShowImage" = "画像を表示"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; @@ -107,11 +114,13 @@ "Common.Controls.Status.Actions.Unfavorite" = "お気に入り登録を取り消す"; "Common.Controls.Status.Actions.Unreblog" = "ブーストを戻す"; "Common.Controls.Status.ContentWarning" = "コンテンツ警告"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "どこかをタップして表示"; -"Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; -"Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; -"Common.Controls.Status.MetaEntity.Mention" = "Show Profile: %@"; -"Common.Controls.Status.MetaEntity.Url" = "Link: %@"; +"Common.Controls.Status.MetaEntity.Email" = "メールアドレス: %@"; +"Common.Controls.Status.MetaEntity.Hashtag" = "ハッシュタグ: %@"; +"Common.Controls.Status.MetaEntity.Mention" = "プロフィールを表示: %@"; +"Common.Controls.Status.MetaEntity.Url" = "リンク: %@"; "Common.Controls.Status.Poll.Closed" = "終了"; "Common.Controls.Status.Poll.Vote" = "投票"; "Common.Controls.Status.SensitiveContent" = "閲覧注意"; @@ -124,6 +133,10 @@ "Common.Controls.Status.Tag.Mention" = "メンション"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "タップして表示"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@がブースト"; "Common.Controls.Status.UserRepliedTo" = "%@に返信"; "Common.Controls.Status.Visibility.Direct" = "この投稿はメンションされたユーザーに限り見ることができます。"; @@ -131,9 +144,9 @@ "Common.Controls.Status.Visibility.PrivateFromMe" = "この投稿はフォロワーに限り見ることができます。"; "Common.Controls.Status.Visibility.Unlisted" = "この投稿は誰でも見ることができますが、公開タイムラインには表示されません。"; "Common.Controls.Tabs.Home" = "ホーム"; -"Common.Controls.Tabs.Notification" = "通知"; +"Common.Controls.Tabs.Notifications" = "通知"; "Common.Controls.Tabs.Profile" = "プロフィール"; -"Common.Controls.Tabs.Search" = "検索"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "Common.Controls.Timeline.Filtered" = "フィルター済み"; "Common.Controls.Timeline.Header.BlockedWarning" = "ブロックされているようです..."; "Common.Controls.Timeline.Header.BlockingWarning" = "ブロックを解除するまでこのユーザーをみることはできません。 @@ -151,32 +164,32 @@ "Scene.AccountList.AddAccount" = "アカウントを追加"; "Scene.AccountList.DismissAccountSwitcher" = "アカウント切替画面を閉じます"; "Scene.AccountList.TabBarHint" = "現在のアカウント: %@. ダブルタップしてアカウント切替画面を表示します"; -"Scene.Bookmark.Title" = "Bookmarks"; -"Scene.Compose.Accessibility.AppendAttachment" = "アタッチメントの追加"; +"Scene.Bookmark.Title" = "ブックマーク"; +"Scene.Compose.Accessibility.AppendAttachment" = "添付ファイルを追加"; "Scene.Compose.Accessibility.AppendPoll" = "投票を追加"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "カスタム絵文字ピッカー"; "Scene.Compose.Accessibility.DisableContentWarning" = "閲覧注意を無効にする"; "Scene.Compose.Accessibility.EnableContentWarning" = "閲覧注意を有効にする"; -"Scene.Compose.Accessibility.PostOptions" = "Post Options"; +"Scene.Compose.Accessibility.PostOptions" = "投稿オプション"; "Scene.Compose.Accessibility.PostVisibilityMenu" = "投稿の表示メニュー"; "Scene.Compose.Accessibility.PostingAs" = "Posting as %@"; "Scene.Compose.Accessibility.RemovePoll" = "投票を消去"; "Scene.Compose.Attachment.AttachmentBroken" = "%@は壊れていてMastodonにアップロードできません。"; -"Scene.Compose.Attachment.AttachmentTooLarge" = "Attachment too large"; +"Scene.Compose.Attachment.AttachmentTooLarge" = "添付ファイルが大きすぎます"; "Scene.Compose.Attachment.CanNotRecognizeThisMediaAttachment" = "Can not recognize this media attachment"; "Scene.Compose.Attachment.CompressingState" = "Compressing..."; "Scene.Compose.Attachment.DescriptionPhoto" = "閲覧が難しいユーザーへの画像説明"; "Scene.Compose.Attachment.DescriptionVideo" = "閲覧が難しいユーザーへの映像説明"; -"Scene.Compose.Attachment.LoadFailed" = "Load Failed"; +"Scene.Compose.Attachment.LoadFailed" = "読み込みに失敗しました"; "Scene.Compose.Attachment.Photo" = "写真"; "Scene.Compose.Attachment.ServerProcessingState" = "Server Processing..."; -"Scene.Compose.Attachment.UploadFailed" = "Upload Failed"; +"Scene.Compose.Attachment.UploadFailed" = "アップロードに失敗しました"; "Scene.Compose.Attachment.Video" = "動画"; "Scene.Compose.AutoComplete.SpaceToAdd" = "スペースを追加"; "Scene.Compose.ComposeAction" = "投稿"; "Scene.Compose.ContentInputPlaceholder" = "気になることを入力またはペースト"; "Scene.Compose.ContentWarning.Placeholder" = "ここに警告を書いてください..."; -"Scene.Compose.Keyboard.AppendAttachmentEntry" = "アタッチメントを追加 - %@"; +"Scene.Compose.Keyboard.AppendAttachmentEntry" = "添付ファイルを追加 - %@"; "Scene.Compose.Keyboard.DiscardPost" = "投稿を破棄"; "Scene.Compose.Keyboard.PublishPost" = "投稿する"; "Scene.Compose.Keyboard.SelectVisibilityEntry" = "公開設定を選択 - %@"; @@ -212,7 +225,7 @@ "Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "メールアプリを開く"; "Scene.ConfirmEmail.OpenEmailApp.Title" = "メールを確認"; "Scene.ConfirmEmail.Subtitle" = "先程 %@ にメールを送信しました。リンクをタップしてアカウントを確認してください。"; -"Scene.ConfirmEmail.TapTheLinkWeEmailedToYouToVerifyYourAccount" = "Tap the link we emailed to you to verify your account"; +"Scene.ConfirmEmail.TapTheLinkWeEmailedToYouToVerifyYourAccount" = "メールで送られたリンクへアクセスし、アカウントを認証してください"; "Scene.ConfirmEmail.Title" = "さいごにもうひとつ。"; "Scene.Discovery.Intro" = "あなたのMastodonサーバーで注目を集めている投稿がここに表示されます。"; "Scene.Discovery.Tabs.Community" = "コミュニティ"; @@ -223,7 +236,13 @@ "Scene.Familiarfollowers.FollowedByNames" = "Followed by %@"; "Scene.Familiarfollowers.Title" = "Followers you familiar"; "Scene.Favorite.Title" = "お気に入り"; -"Scene.FavoritedBy.Title" = "Favorited By"; +"Scene.FavoritedBy.Title" = "お気に入り"; +"Scene.FollowedTags.Actions.Follow" = "Follow"; +"Scene.FollowedTags.Actions.Unfollow" = "Unfollow"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "posts"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Followed Tags"; "Scene.Follower.Footer" = "他のサーバーからのフォロワーは表示されません。"; "Scene.Follower.Title" = "フォロワー"; "Scene.Following.Footer" = "他のサーバーにいるフォローは表示されません。"; @@ -235,8 +254,8 @@ "Scene.HomeTimeline.NavigationBarState.Published" = "投稿しました!"; "Scene.HomeTimeline.NavigationBarState.Publishing" = "投稿中..."; "Scene.HomeTimeline.Title" = "ホーム"; -"Scene.Login.ServerSearchField.Placeholder" = "Enter URL or search for your server"; -"Scene.Login.Subtitle" = "Log you in on the server you created your account on."; +"Scene.Login.ServerSearchField.Placeholder" = "URLを入力またはサーバーを検索"; +"Scene.Login.Subtitle" = "アカウントを作成したサーバーにログインします。"; "Scene.Login.Title" = "Welcome back"; "Scene.Notification.FollowRequest.Accept" = "承認"; "Scene.Notification.FollowRequest.Accepted" = "承諾済み"; @@ -263,6 +282,7 @@ "Scene.Profile.Dashboard.Following" = "フォロー"; "Scene.Profile.Dashboard.Posts" = "投稿"; "Scene.Profile.Fields.AddRow" = "行追加"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "コンテンツ"; "Scene.Profile.Fields.Placeholder.Label" = "ラベル"; "Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %@"; @@ -270,12 +290,12 @@ "Scene.Profile.Header.FollowsYou" = "フォローされています"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "%@をブロックしますか?"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "アカウントをブロック"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Confirm to hide reblogs"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Hide Reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "ブーストを非表示にしますか?"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "ブーストを非表示"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "%@をミュートしますか?"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "アカウントをミュート"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Confirm to show reblogs"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Show Reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "ブーストを表示しますか?"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "ブーストを表示"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "%@のブロックを解除しますか?"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "アカウントのブロックを解除"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "%@をミュートしますか?"; @@ -285,7 +305,7 @@ "Scene.Profile.SegmentedControl.Posts" = "投稿"; "Scene.Profile.SegmentedControl.PostsAndReplies" = "投稿と返信"; "Scene.Profile.SegmentedControl.Replies" = "返信"; -"Scene.RebloggedBy.Title" = "Reblogged By"; +"Scene.RebloggedBy.Title" = "ブースト"; "Scene.Register.Error.Item.Agreement" = "契約"; "Scene.Register.Error.Item.Email" = "メール"; "Scene.Register.Error.Item.Locale" = "地域"; @@ -329,15 +349,15 @@ "Scene.Report.Step1" = "ステップ 1/2"; "Scene.Report.Step2" = "ステップ 2/2"; "Scene.Report.StepFinal.BlockUser" = "%@をブロック"; -"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "見えないようにしたいですか?"; "Scene.Report.StepFinal.MuteUser" = "%@をミュート"; -"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "相手はあなたの投稿を見たり、フォローしたりできなくなります。あなたにブロックされていることはわかります。"; "Scene.Report.StepFinal.Unfollow" = "フォロー解除"; "Scene.Report.StepFinal.UnfollowUser" = "%@をフォロー解除"; "Scene.Report.StepFinal.Unfollowed" = "フォロー解除しました"; -"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "Mastodonで気に入らないものを見た場合、その人をあなたの体験から取り除くことができます。"; "Scene.Report.StepFinal.WhileWeReviewThisYouCanTakeActionAgainstUser" = "私たちが確認している間でも、あなたは%@さんに対して対応することができます。"; -"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "ホームに投稿やブーストは表示されなくなります。相手にミュートしたことは伝わりません。"; "Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "その他に私たちに伝えておくべき事はありますか?"; "Scene.Report.StepFour.Step4Of4" = "ステップ 4/4"; "Scene.Report.StepOne.IDontLikeIt" = "興味がありません"; @@ -353,11 +373,11 @@ "Scene.Report.StepOne.WhatsWrongWithThisPost" = "この投稿のどこが問題ですか?"; "Scene.Report.StepOne.WhatsWrongWithThisUsername" = "%@さんのどこが問題ですか?"; "Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "ルールに違反しているのを見つけた場合"; -"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; -"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "この通報を裏付けるような投稿はありますか?"; +"Scene.Report.StepThree.SelectAllThatApply" = "当てはまるものをすべて選んでください"; "Scene.Report.StepThree.Step3Of4" = "ステップ 3/4"; -"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; -"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "興味がありません"; +"Scene.Report.StepTwo.SelectAllThatApply" = "当てはまるものをすべて選んでください"; "Scene.Report.StepTwo.Step2Of4" = "ステップ 2/4"; "Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "どのルールに違反していますか?"; "Scene.Report.TextPlaceholder" = "追加コメントを入力"; @@ -399,11 +419,11 @@ "Scene.ServerPicker.EmptyState.BadNetwork" = "データの読み込み中に何か問題が発生しました。インターネットの接続状況を確認してください。"; "Scene.ServerPicker.EmptyState.FindingServers" = "利用可能なサーバーの検索..."; "Scene.ServerPicker.EmptyState.NoResults" = "なし"; -"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "コミュニティを検索またはURLを入力"; "Scene.ServerPicker.Label.Category" = "カテゴリー"; "Scene.ServerPicker.Label.Language" = "言語"; "Scene.ServerPicker.Label.Users" = "ユーザー"; -"Scene.ServerPicker.Subtitle" = "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers."; +"Scene.ServerPicker.Subtitle" = "お住まいの地域、興味、目的に基づいてサーバーを選択してください。 サーバーに関係なく、Mastodonの誰とでも話せます。"; "Scene.ServerPicker.Title" = "サーバーを選択"; "Scene.ServerRules.Button.Confirm" = "同意する"; "Scene.ServerRules.PrivacyPolicy" = "プライバシーポリシー"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings index 781143b71..43a1d385a 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings @@ -22,6 +22,9 @@ Ma ulac aɣilif, senqed tuqqna-inek internet."; "Common.Alerts.SignOut.Message" = "Tebɣiḍ ad teffɣeḍ?"; "Common.Alerts.SignOut.Title" = "Ffeɣ"; "Common.Alerts.SignUpFailure.Title" = "Tuccḍa deg unekcum"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "Tafrant tfuk"; "Common.Alerts.VoteFailure.Title" = "Tuccḍa deg ufran"; "Common.Controls.Actions.Add" = "Rnu"; @@ -31,6 +34,7 @@ Ma ulac aɣilif, senqed tuqqna-inek internet."; "Common.Controls.Actions.Compose" = "Sudes"; "Common.Controls.Actions.Confirm" = "Sentem"; "Common.Controls.Actions.Continue" = "Kemmel"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "Nɣel tawlaft"; "Common.Controls.Actions.Delete" = "Kkes"; "Common.Controls.Actions.Discard" = "Sefsex"; @@ -59,6 +63,8 @@ Ma ulac aɣilif, senqed tuqqna-inek internet."; "Common.Controls.Actions.SignUp" = "Snulfu-d amiḍan"; "Common.Controls.Actions.Skip" = "Zgel"; "Common.Controls.Actions.TakePhoto" = "Ṭṭef tawlaft"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "Ɛreḍ tikkelt-nniḍen"; "Common.Controls.Actions.UnblockDomain" = "Serreḥ i %@"; "Common.Controls.Friendship.Block" = "Sewḥel"; @@ -100,6 +106,7 @@ Ma ulac aɣilif, senqed tuqqna-inek internet."; "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.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "Sken GIF"; "Common.Controls.Status.Actions.ShowImage" = "Sken tugna"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Sken ameɣri n tvidyut"; @@ -107,6 +114,8 @@ Ma ulac aɣilif, senqed tuqqna-inek internet."; "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.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "Sit anida tebɣiḍ i wakken ad twaliḍ"; "Common.Controls.Status.MetaEntity.Email" = "Tansa imayl : %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Ahacṭag : %@"; @@ -124,6 +133,10 @@ Ma ulac aɣilif, senqed tuqqna-inek internet."; "Common.Controls.Status.Tag.Mention" = "Tabdart"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Sit i uskan"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "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."; @@ -131,9 +144,9 @@ Ma ulac aɣilif, senqed tuqqna-inek internet."; "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.Notifications" = "Notifications"; "Common.Controls.Tabs.Profile" = "Amaɣnu"; -"Common.Controls.Tabs.Search" = "Nadi"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "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."; @@ -229,6 +242,12 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.Familiarfollowers.Title" = "Ineḍfaren i tessneḍ"; "Scene.Favorite.Title" = "Ismenyifen-ik·im"; "Scene.FavoritedBy.Title" = "Ismenyaf-it"; +"Scene.FollowedTags.Actions.Follow" = "Follow"; +"Scene.FollowedTags.Actions.Unfollow" = "Unfollow"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "posts"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Followed Tags"; "Scene.Follower.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; "Scene.Follower.Title" = "aneḍfar"; "Scene.Following.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; @@ -268,6 +287,7 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.Profile.Dashboard.Following" = "iṭafaṛ"; "Scene.Profile.Dashboard.Posts" = "tisuffaɣ"; "Scene.Profile.Fields.AddRow" = "Rnu izirig"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "Agbur"; "Scene.Profile.Fields.Placeholder.Label" = "Tabzimt"; "Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings index 03ac1f46d..6eaa474f0 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings @@ -22,6 +22,9 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Alerts.SignOut.Message" = "Ma tu dixwazî ku derkevî?"; "Common.Alerts.SignOut.Title" = "Derkeve"; "Common.Alerts.SignUpFailure.Title" = "Tomarkirin têkçû"; +"Common.Alerts.TranslationFailed.Button" = "BAŞ E"; +"Common.Alerts.TranslationFailed.Message" = "Werger têk çû. Dibe ku rêvebir werger li ser vê rajakarê çalak nekiribe an jî ev rajakar guhertoyek kevntir a Mastodon e ku werger hîn nehatiye piştgirîkirin."; +"Common.Alerts.TranslationFailed.Title" = "Nîşe"; "Common.Alerts.VoteFailure.PollEnded" = "Rapirsîya qediya"; "Common.Alerts.VoteFailure.Title" = "Dengdayîn têkçû"; "Common.Controls.Actions.Add" = "Tevlî bike"; @@ -31,6 +34,7 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Actions.Compose" = "Binivîsîne"; "Common.Controls.Actions.Confirm" = "Bipejirîne"; "Common.Controls.Actions.Continue" = "Bidomîne"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "Wêneyê jê bigire"; "Common.Controls.Actions.Delete" = "Jê bibe"; "Common.Controls.Actions.Discard" = "Biavêje"; @@ -59,6 +63,8 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Actions.SignUp" = "Ajimêr biafirîne"; "Common.Controls.Actions.Skip" = "Derbas bike"; "Common.Controls.Actions.TakePhoto" = "Wêne bikişîne"; +"Common.Controls.Actions.TranslatePost.Title" = "Ji %@ hate wergerandin"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Nenas"; "Common.Controls.Actions.TryAgain" = "Dîsa biceribîne"; "Common.Controls.Actions.UnblockDomain" = "%@ asteng neke"; "Common.Controls.Friendship.Block" = "Asteng bike"; @@ -100,6 +106,7 @@ 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.ShareLinkInPost" = "Share Link in Post"; "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"; @@ -107,6 +114,8 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Status.Actions.Unfavorite" = "Nebijarte"; "Common.Controls.Status.Actions.Unreblog" = "Ji nû ve nivîsandinê vegere"; "Common.Controls.Status.ContentWarning" = "Hişyariya naverokê"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "Ji bo eşkerekirinê li derekî bitikîne"; "Common.Controls.Status.MetaEntity.Email" = "Navnîşanên e-nameyê: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtagê: %@"; @@ -124,6 +133,10 @@ Jkx girêdana înternetê xwe kontrol bike."; "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.Translation.ShowOriginal" = "A resen nîşan bide"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Nenas"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "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."; @@ -131,9 +144,9 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Tenê şopînerên min dikarin vê şandiyê bibînin."; "Common.Controls.Status.Visibility.Unlisted" = "Her kes dikare vê şandiyê bibîne lê nayê nîşandan di demnameya gelemperî de."; "Common.Controls.Tabs.Home" = "Serrûpel"; -"Common.Controls.Tabs.Notification" = "Agahdarî"; +"Common.Controls.Tabs.Notifications" = "Agahdarî"; "Common.Controls.Tabs.Profile" = "Profîl"; -"Common.Controls.Tabs.Search" = "Bigere"; +"Common.Controls.Tabs.SearchAndExplore" = "Bigere û vekole"; "Common.Controls.Timeline.Filtered" = "Parzûnkirî"; "Common.Controls.Timeline.Header.BlockedWarning" = "Tu nikarî profîla vî/ê bikarhênerî bibînî heya ku ew astengiyê li ser te rakin."; @@ -230,6 +243,12 @@ girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.Familiarfollowers.Title" = "Şopînerên ku tu wan nas dikî"; "Scene.Favorite.Title" = "Bijarteyên te"; "Scene.FavoritedBy.Title" = "Hatiye hezkirin ji aliyê"; +"Scene.FollowedTags.Actions.Follow" = "Bişopîne"; +"Scene.FollowedTags.Actions.Unfollow" = "Neşopîne"; +"Scene.FollowedTags.Header.Participants" = "beşdar"; +"Scene.FollowedTags.Header.Posts" = "şandî"; +"Scene.FollowedTags.Header.PostsToday" = "şandiyên îro"; +"Scene.FollowedTags.Title" = "Hashtagên şopandî"; "Scene.Follower.Footer" = "Şopîner ji rajekerên din nayê dîtin."; "Scene.Follower.Title" = "şopîner"; "Scene.Following.Footer" = "Şopandin ji rajekerên din nayê dîtin."; @@ -269,6 +288,7 @@ girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.Profile.Dashboard.Following" = "dişopîne"; "Scene.Profile.Dashboard.Posts" = "şandî"; "Scene.Profile.Fields.AddRow" = "Rêzê tevlî bike"; +"Scene.Profile.Fields.Joined" = "Dîroka tevlîbûnê"; "Scene.Profile.Fields.Placeholder.Content" = "Naverok"; "Scene.Profile.Fields.Placeholder.Label" = "Nîşan"; "Scene.Profile.Fields.Verified.Long" = "Xwedaniya li vê girêdanê di %@ de hatiye kontrolkirin"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings index 0d8f1dd0f..6e7839852 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings @@ -21,6 +21,9 @@ "Common.Alerts.SignOut.Message" = "Weet je zeker dat je wilt uitloggen?"; "Common.Alerts.SignOut.Title" = "Log-uit"; "Common.Alerts.SignUpFailure.Title" = "Registratiefout"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "De peiling is beëindigd"; "Common.Alerts.VoteFailure.Title" = "Stemmen Mislukt"; "Common.Controls.Actions.Add" = "Voeg toe"; @@ -30,6 +33,7 @@ "Common.Controls.Actions.Compose" = "Schrijf bericht"; "Common.Controls.Actions.Confirm" = "Bevestigen"; "Common.Controls.Actions.Continue" = "Ga verder"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "Kopieer foto"; "Common.Controls.Actions.Delete" = "Verwijder"; "Common.Controls.Actions.Discard" = "Weggooien"; @@ -54,10 +58,12 @@ "Common.Controls.Actions.Share" = "Deel"; "Common.Controls.Actions.SharePost" = "Deel bericht"; "Common.Controls.Actions.ShareUser" = "Delen %@"; -"Common.Controls.Actions.SignIn" = "Log in"; -"Common.Controls.Actions.SignUp" = "Create account"; +"Common.Controls.Actions.SignIn" = "Inloggen"; +"Common.Controls.Actions.SignUp" = "Account aanmaken"; "Common.Controls.Actions.Skip" = "Overslaan"; "Common.Controls.Actions.TakePhoto" = "Maak foto"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "Probeer Opnieuw"; "Common.Controls.Actions.UnblockDomain" = "Deblokkeer %@"; "Common.Controls.Friendship.Block" = "Blokkeren"; @@ -67,13 +73,13 @@ "Common.Controls.Friendship.EditInfo" = "Bewerken"; "Common.Controls.Friendship.Follow" = "Volgen"; "Common.Controls.Friendship.Following" = "Gevolgd"; -"Common.Controls.Friendship.HideReblogs" = "Hide Reblogs"; +"Common.Controls.Friendship.HideReblogs" = "Verberg reblogs"; "Common.Controls.Friendship.Mute" = "Negeren"; "Common.Controls.Friendship.MuteUser" = "Negeer %@"; "Common.Controls.Friendship.Muted" = "Genegeerd"; "Common.Controls.Friendship.Pending" = "In afwachting"; "Common.Controls.Friendship.Request" = "Verzoeken"; -"Common.Controls.Friendship.ShowReblogs" = "Show Reblogs"; +"Common.Controls.Friendship.ShowReblogs" = "Toon reblogs"; "Common.Controls.Friendship.Unblock" = "Deblokkeer"; "Common.Controls.Friendship.UnblockUser" = "Deblokkeer %@"; "Common.Controls.Friendship.Unmute" = "Niet langer negeren"; @@ -99,6 +105,7 @@ "Common.Controls.Status.Actions.Menu" = "Menu"; "Common.Controls.Status.Actions.Reblog" = "Delen"; "Common.Controls.Status.Actions.Reply" = "Reageren"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "GIF weergeven"; "Common.Controls.Status.Actions.ShowImage" = "Toon afbeelding"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Toon videospeler"; @@ -106,10 +113,12 @@ "Common.Controls.Status.Actions.Unfavorite" = "Verwijderen uit Favorieten"; "Common.Controls.Status.Actions.Unreblog" = "Delen ongedaan maken"; "Common.Controls.Status.ContentWarning" = "Inhoudswaarschuwing"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "Tap hier om te tonen"; -"Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; +"Common.Controls.Status.MetaEntity.Email" = "E-mailadres: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; -"Common.Controls.Status.MetaEntity.Mention" = "Show Profile: %@"; +"Common.Controls.Status.MetaEntity.Mention" = "Profiel weergeven: %@"; "Common.Controls.Status.MetaEntity.Url" = "Link: %@"; "Common.Controls.Status.Poll.Closed" = "Gesloten"; "Common.Controls.Status.Poll.Vote" = "Stemmen"; @@ -123,6 +132,10 @@ "Common.Controls.Status.Tag.Mention" = "Vermelden"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Tik om te onthullen"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ heeft gedeeld"; "Common.Controls.Status.UserRepliedTo" = "Reactie op %@"; "Common.Controls.Status.Visibility.Direct" = "Alleen de vermelde persoon kan dit bericht zien."; @@ -130,9 +143,9 @@ "Common.Controls.Status.Visibility.PrivateFromMe" = "Alleen mijn volgers kunnen dit bericht zien."; "Common.Controls.Status.Visibility.Unlisted" = "Iedereen kan dit bericht zien maar het wordt niet in de publieke tijdlijn getoond."; "Common.Controls.Tabs.Home" = "Start"; -"Common.Controls.Tabs.Notification" = "Melding"; +"Common.Controls.Tabs.Notifications" = "Notifications"; "Common.Controls.Tabs.Profile" = "Profiel"; -"Common.Controls.Tabs.Search" = "Zoek"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "Common.Controls.Timeline.Filtered" = "Gefilterd"; "Common.Controls.Timeline.Header.BlockedWarning" = "U kunt het profiel van deze gebruiker niet bekijken zolang u geblokkeerd bent."; "Common.Controls.Timeline.Header.BlockingWarning" = "U kunt het profiel van deze geblokkeerde gebruiker niet bekijken. @@ -156,20 +169,20 @@ Uw profiel ziet er zo uit voor hen."; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Eigen Emojikiezer"; "Scene.Compose.Accessibility.DisableContentWarning" = "Inhoudswaarschuwing Uitschakelen"; "Scene.Compose.Accessibility.EnableContentWarning" = "Inhoudswaarschuwing inschakelen"; -"Scene.Compose.Accessibility.PostOptions" = "Post Options"; +"Scene.Compose.Accessibility.PostOptions" = "Plaats Bericht Opties"; "Scene.Compose.Accessibility.PostVisibilityMenu" = "Berichtzichtbaarheidsmenu"; -"Scene.Compose.Accessibility.PostingAs" = "Posting as %@"; +"Scene.Compose.Accessibility.PostingAs" = "Plaats bericht als %@"; "Scene.Compose.Accessibility.RemovePoll" = "Peiling verwijderen"; "Scene.Compose.Attachment.AttachmentBroken" = "Deze %@ is corrupt en kan niet geüpload worden naar Mastodon."; -"Scene.Compose.Attachment.AttachmentTooLarge" = "Attachment too large"; -"Scene.Compose.Attachment.CanNotRecognizeThisMediaAttachment" = "Can not recognize this media attachment"; -"Scene.Compose.Attachment.CompressingState" = "Compressing..."; +"Scene.Compose.Attachment.AttachmentTooLarge" = "Bijlage te groot"; +"Scene.Compose.Attachment.CanNotRecognizeThisMediaAttachment" = "Kan de media in de bijlage niet herkennen"; +"Scene.Compose.Attachment.CompressingState" = "Bezig met comprimeren..."; "Scene.Compose.Attachment.DescriptionPhoto" = "Omschrijf de foto voor mensen met een visuele beperking..."; "Scene.Compose.Attachment.DescriptionVideo" = "Omschrijf de video voor mensen met een visuele beperking..."; -"Scene.Compose.Attachment.LoadFailed" = "Load Failed"; +"Scene.Compose.Attachment.LoadFailed" = "Laden mislukt"; "Scene.Compose.Attachment.Photo" = "foto"; -"Scene.Compose.Attachment.ServerProcessingState" = "Server Processing..."; -"Scene.Compose.Attachment.UploadFailed" = "Upload Failed"; +"Scene.Compose.Attachment.ServerProcessingState" = "Server is bezig met verwerken..."; +"Scene.Compose.Attachment.UploadFailed" = "Uploaden mislukt"; "Scene.Compose.Attachment.Video" = "video"; "Scene.Compose.AutoComplete.SpaceToAdd" = "Spaties toe te voegen"; "Scene.Compose.ComposeAction" = "Publiceren"; @@ -190,8 +203,8 @@ Uw profiel ziet er zo uit voor hen."; "Scene.Compose.Poll.OptionNumber" = "Optie %ld"; "Scene.Compose.Poll.SevenDays" = "7 Dagen"; "Scene.Compose.Poll.SixHours" = "6 Uur"; -"Scene.Compose.Poll.ThePollHasEmptyOption" = "The poll has empty option"; -"Scene.Compose.Poll.ThePollIsInvalid" = "The poll is invalid"; +"Scene.Compose.Poll.ThePollHasEmptyOption" = "De peiling heeft een lege optie"; +"Scene.Compose.Poll.ThePollIsInvalid" = "De peiling is ongeldig"; "Scene.Compose.Poll.ThirtyMinutes" = "30 minuten"; "Scene.Compose.Poll.ThreeDays" = "3 Dagen"; "Scene.Compose.ReplyingToUser" = "reageren op %@"; @@ -212,36 +225,42 @@ Uw profiel ziet er zo uit voor hen."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Ga naar uw inbox."; "Scene.ConfirmEmail.Subtitle" = "We hebben een e-mail gestuurd naar %@, klik op de link om uw account te bevestigen."; -"Scene.ConfirmEmail.TapTheLinkWeEmailedToYouToVerifyYourAccount" = "Tap the link we emailed to you to verify your account"; +"Scene.ConfirmEmail.TapTheLinkWeEmailedToYouToVerifyYourAccount" = "Tik op de link in de e-mail die je hebt ontvangen om uw account te verifiëren"; "Scene.ConfirmEmail.Title" = "Nog één ding."; "Scene.Discovery.Intro" = "Dit zijn de berichten die populair zijn in jouw Mastodon-kringen."; -"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Tabs.Community" = "Gemeenschap"; "Scene.Discovery.Tabs.ForYou" = "Voor jou"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "Nieuws"; "Scene.Discovery.Tabs.Posts" = "Berichten"; -"Scene.Familiarfollowers.FollowedByNames" = "Followed by %@"; -"Scene.Familiarfollowers.Title" = "Followers you familiar"; +"Scene.Familiarfollowers.FollowedByNames" = "Gevolgd door %@"; +"Scene.Familiarfollowers.Title" = "Volgers die je kent"; "Scene.Favorite.Title" = "Uw favorieten"; "Scene.FavoritedBy.Title" = "Favorited By"; +"Scene.FollowedTags.Actions.Follow" = "Follow"; +"Scene.FollowedTags.Actions.Unfollow" = "Unfollow"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "posts"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Followed Tags"; "Scene.Follower.Footer" = "Volgers van andere servers worden niet weergegeven."; -"Scene.Follower.Title" = "follower"; +"Scene.Follower.Title" = "volger"; "Scene.Following.Footer" = "Volgers van andere servers worden niet weergegeven."; -"Scene.Following.Title" = "following"; -"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; -"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; +"Scene.Following.Title" = "volgend"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tik om naar boven te scrollen en tik nogmaals om terug te keren naar de vorige locatie"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo knop"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Bekijk nieuwe berichten"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; "Scene.HomeTimeline.NavigationBarState.Published" = "Gepubliceerd!"; "Scene.HomeTimeline.NavigationBarState.Publishing" = "Bericht publiceren..."; "Scene.HomeTimeline.Title" = "Start"; -"Scene.Login.ServerSearchField.Placeholder" = "Enter URL or search for your server"; -"Scene.Login.Subtitle" = "Log you in on the server you created your account on."; -"Scene.Login.Title" = "Welcome back"; -"Scene.Notification.FollowRequest.Accept" = "Accept"; -"Scene.Notification.FollowRequest.Accepted" = "Accepted"; -"Scene.Notification.FollowRequest.Reject" = "reject"; -"Scene.Notification.FollowRequest.Rejected" = "Rejected"; +"Scene.Login.ServerSearchField.Placeholder" = "Voer URL in of zoek naar uw server"; +"Scene.Login.Subtitle" = "Log je in op de server waarop je je account hebt aangemaakt."; +"Scene.Login.Title" = "Welkom terug"; +"Scene.Notification.FollowRequest.Accept" = "Accepteren"; +"Scene.Notification.FollowRequest.Accepted" = "Geaccepteerd"; +"Scene.Notification.FollowRequest.Reject" = "afwijzen"; +"Scene.Notification.FollowRequest.Rejected" = "Afgewezen"; "Scene.Notification.Keyobard.ShowEverything" = "Alles weergeven"; "Scene.Notification.Keyobard.ShowMentions" = "Vermeldingen weergeven"; "Scene.Notification.NotificationDescription.FavoritedYourPost" = "heeft je bericht als favoriet gemrkeerd"; @@ -263,19 +282,20 @@ klik op de link om uw account te bevestigen."; "Scene.Profile.Dashboard.Following" = "volgend"; "Scene.Profile.Dashboard.Posts" = "berichten"; "Scene.Profile.Fields.AddRow" = "Rij Toevoegen"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "Inhoud"; "Scene.Profile.Fields.Placeholder.Label" = "Etiket"; -"Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %@"; -"Scene.Profile.Fields.Verified.Short" = "Verified on %@"; -"Scene.Profile.Header.FollowsYou" = "Follows You"; +"Scene.Profile.Fields.Verified.Long" = "Eigendom van deze link is gecontroleerd op %@"; +"Scene.Profile.Fields.Verified.Short" = "Geverifieerd op %@"; +"Scene.Profile.Header.FollowsYou" = "Volgt jou"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Bevestig om %@ te blokkeren"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Blokkeer account"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Confirm to hide reblogs"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Hide Reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Bevestig om reblogs te verbergen"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Verberg reblogs"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Bevestig om %@ te negeren"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Negeer account"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Confirm to show reblogs"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Show Reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Bevestig om reblogs te tonen"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Toon reblogs"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Bevestig om %@ te deblokkeren"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Deblokkeer Account"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Bevestig om %@ te negeren"; @@ -318,7 +338,7 @@ klik op de link om uw account te bevestigen."; "Scene.Register.Input.Password.Require" = "Je wachtwoord moet ten minste:"; "Scene.Register.Input.Username.DuplicatePrompt" = "Deze gebruikersnaam is al in gebruik."; "Scene.Register.Input.Username.Placeholder" = "gebruikersnaam"; -"Scene.Register.LetsGetYouSetUpOnDomain" = "Let’s get you set up on %@"; +"Scene.Register.LetsGetYouSetUpOnDomain" = "Laten we je account instellen op %@"; "Scene.Register.Title" = "Vertel ons over uzelf."; "Scene.Report.Content1" = "Zijn er nog meer berichten die u aan het rapport wilt toevoegen?"; "Scene.Report.Content2" = "Is er iets anders over dit rapport dat de moderators zouden moeten weten?"; @@ -346,12 +366,12 @@ klik op de link om uw account te bevestigen."; "Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; "Scene.Report.StepOne.ItsSpam" = "It’s spam"; "Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; -"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; -"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Selecteer de beste overeenkomst"; +"Scene.Report.StepOne.Step1Of4" = "Stap 1 van 4"; "Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; -"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; -"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; -"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "Wat is er mis met dit bericht?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "Wat is er mis met dit bericht?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "Wat is er mis met %@?"; "Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; "Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; "Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; @@ -399,11 +419,11 @@ klik op de link om uw account te bevestigen."; "Scene.ServerPicker.EmptyState.BadNetwork" = "Er is een fout opgetreden bij het laden van de gegevens. Controleer uw internetverbinding."; "Scene.ServerPicker.EmptyState.FindingServers" = "Beschikbare servers zoeken..."; "Scene.ServerPicker.EmptyState.NoResults" = "Geen resultaten"; -"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Zoek naar gemeenschappen of voer URL in"; "Scene.ServerPicker.Label.Category" = "CATEGORIE"; "Scene.ServerPicker.Label.Language" = "TAAL"; "Scene.ServerPicker.Label.Users" = "GEBRUIKERS"; -"Scene.ServerPicker.Subtitle" = "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers."; +"Scene.ServerPicker.Subtitle" = "Kies een server gebaseerd op je regio, interesses, of een algemene server. Je kunt nog steeds chatten met iedereen op Mastodon, ongeacht op welke server je zit."; "Scene.ServerPicker.Title" = "Kies een server, welke dan ook."; "Scene.ServerRules.Button.Confirm" = "Ik Ga Akkoord"; "Scene.ServerRules.PrivacyPolicy" = "privacybeleid"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.stringsdict index 84769b0c1..29d0ec841 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.stringsdict @@ -15,7 +15,7 @@ one 1 unread notification other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings index 2ad16cb77..8275902d4 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings @@ -22,6 +22,9 @@ "Common.Alerts.SignOut.Message" = "Вы действительно хотите выйти из учётной записи?"; "Common.Alerts.SignOut.Title" = "Выход"; "Common.Alerts.SignUpFailure.Title" = "Ошибка регистрации"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "Опрос уже завершился"; "Common.Alerts.VoteFailure.Title" = "Не удалось проголосовать"; "Common.Controls.Actions.Add" = "Добавить"; @@ -31,6 +34,7 @@ "Common.Controls.Actions.Compose" = "Написать"; "Common.Controls.Actions.Confirm" = "Подтвердить"; "Common.Controls.Actions.Continue" = "Продолжить"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "Скопировать изображение"; "Common.Controls.Actions.Delete" = "Удалить"; "Common.Controls.Actions.Discard" = "Отмена"; @@ -59,6 +63,8 @@ "Common.Controls.Actions.SignUp" = "Create account"; "Common.Controls.Actions.Skip" = "Пропустить"; "Common.Controls.Actions.TakePhoto" = "Сделать фото"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "Попробовать снова"; "Common.Controls.Actions.UnblockDomain" = "Разблокировать %@"; "Common.Controls.Friendship.Block" = "Заблокировать"; @@ -100,6 +106,7 @@ "Common.Controls.Status.Actions.Menu" = "Меню"; "Common.Controls.Status.Actions.Reblog" = "Продвинуть"; "Common.Controls.Status.Actions.Reply" = "Ответить"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "Показать GIF"; "Common.Controls.Status.Actions.ShowImage" = "Показать изображение"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Показать видеопроигрыватель"; @@ -107,6 +114,8 @@ "Common.Controls.Status.Actions.Unfavorite" = "Убрать из избранного"; "Common.Controls.Status.Actions.Unreblog" = "Убрать продвижение"; "Common.Controls.Status.ContentWarning" = "Предупреждение о содержании"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "Нажмите в любом месте, чтобы показать"; "Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; @@ -124,6 +133,10 @@ "Common.Controls.Status.Tag.Mention" = "Упоминание"; "Common.Controls.Status.Tag.Url" = "Ссылка"; "Common.Controls.Status.TapToReveal" = "Нажмите, чтобы показать"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ продвинул(а)"; "Common.Controls.Status.UserRepliedTo" = "Ответил(а) %@"; "Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; @@ -131,9 +144,9 @@ "Common.Controls.Status.Visibility.PrivateFromMe" = "Only my followers can see this post."; "Common.Controls.Status.Visibility.Unlisted" = "Everyone can see this post but not display in the public timeline."; "Common.Controls.Tabs.Home" = "Главная"; -"Common.Controls.Tabs.Notification" = "Уведомление"; +"Common.Controls.Tabs.Notifications" = "Notifications"; "Common.Controls.Tabs.Profile" = "Профиль"; -"Common.Controls.Tabs.Search" = "Поиск"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "Common.Controls.Timeline.Filtered" = "Отфильтровано"; "Common.Controls.Timeline.Header.BlockedWarning" = "Вы не можете просматривать профиль этого пользователя @@ -240,6 +253,12 @@ "Scene.Familiarfollowers.Title" = "Followers you familiar"; "Scene.Favorite.Title" = "Ваше избранное"; "Scene.FavoritedBy.Title" = "Favorited By"; +"Scene.FollowedTags.Actions.Follow" = "Follow"; +"Scene.FollowedTags.Actions.Unfollow" = "Unfollow"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "posts"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Followed Tags"; "Scene.Follower.Footer" = "Followers from other servers are not displayed."; "Scene.Follower.Title" = "follower"; "Scene.Following.Footer" = "Follows from other servers are not displayed."; @@ -279,6 +298,7 @@ "Scene.Profile.Dashboard.Following" = "подписки"; "Scene.Profile.Dashboard.Posts" = "посты"; "Scene.Profile.Fields.AddRow" = "Добавить строку"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "Содержимое"; "Scene.Profile.Fields.Placeholder.Label" = "Ярлык"; "Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.stringsdict index c9552a9e4..d43386ad9 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.stringsdict @@ -15,11 +15,11 @@ one 1 unread notification few - %ld unread notification + %ld unread notifications many - %ld unread notification + %ld unread notifications other - %ld unread notification + %ld unread notifications a11y.plural.count.input_limit_exceeds diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/sl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/sl.lproj/Localizable.strings index 44f868442..1aa2aab73 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/sl.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/sl.lproj/Localizable.strings @@ -22,6 +22,9 @@ Preverite svojo internetno povezavo."; "Common.Alerts.SignOut.Message" = "Ali ste prepričani, da se želite odjaviti?"; "Common.Alerts.SignOut.Title" = "Odjava"; "Common.Alerts.SignUpFailure.Title" = "Neuspela registracija"; +"Common.Alerts.TranslationFailed.Button" = "V redu"; +"Common.Alerts.TranslationFailed.Message" = "Prevod je spodletel. Morda skrbnik ni omogočil prevajanja na tem strežniku ali pa strežnik teče na starejši različici Masotodona, na kateri prevajanje še ni podprto."; +"Common.Alerts.TranslationFailed.Title" = "Opomba"; "Common.Alerts.VoteFailure.PollEnded" = "Anketa je zaključena"; "Common.Alerts.VoteFailure.Title" = "Napaka glasovanja"; "Common.Controls.Actions.Add" = "Dodaj"; @@ -31,6 +34,7 @@ Preverite svojo internetno povezavo."; "Common.Controls.Actions.Compose" = "Sestavi"; "Common.Controls.Actions.Confirm" = "Potrdi"; "Common.Controls.Actions.Continue" = "Nadaljuj"; +"Common.Controls.Actions.Copy" = "Kopiraj"; "Common.Controls.Actions.CopyPhoto" = "Kopiraj fotografijo"; "Common.Controls.Actions.Delete" = "Izbriši"; "Common.Controls.Actions.Discard" = "Opusti"; @@ -59,6 +63,8 @@ Preverite svojo internetno povezavo."; "Common.Controls.Actions.SignUp" = "Ustvari račun"; "Common.Controls.Actions.Skip" = "Preskoči"; "Common.Controls.Actions.TakePhoto" = "Posnemi fotografijo"; +"Common.Controls.Actions.TranslatePost.Title" = "Prevedi iz: %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Neznano"; "Common.Controls.Actions.TryAgain" = "Poskusi ponovno"; "Common.Controls.Actions.UnblockDomain" = "Odblokiraj %@"; "Common.Controls.Friendship.Block" = "Blokiraj"; @@ -100,6 +106,7 @@ Preverite svojo internetno povezavo."; "Common.Controls.Status.Actions.Menu" = "Meni"; "Common.Controls.Status.Actions.Reblog" = "Poobjavi"; "Common.Controls.Status.Actions.Reply" = "Odgovori"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Deli povezavo v objavi"; "Common.Controls.Status.Actions.ShowGif" = "Pokaži GIF"; "Common.Controls.Status.Actions.ShowImage" = "Pokaži sliko"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Pokaži predvajalnik"; @@ -107,6 +114,8 @@ Preverite svojo internetno povezavo."; "Common.Controls.Status.Actions.Unfavorite" = "Odstrani iz priljubljenih"; "Common.Controls.Status.Actions.Unreblog" = "Razveljavi poobjavo"; "Common.Controls.Status.ContentWarning" = "Opozorilo o vsebini"; +"Common.Controls.Status.LinkViaUser" = "%@ prek %@"; +"Common.Controls.Status.LoadEmbed" = "Naloži vdelano"; "Common.Controls.Status.MediaContentWarning" = "Tapnite kamorkoli, da razkrijete"; "Common.Controls.Status.MetaEntity.Email" = "E-naslov: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Ključnik: %@"; @@ -124,6 +133,10 @@ Preverite svojo internetno povezavo."; "Common.Controls.Status.Tag.Mention" = "Omeni"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Tapnite za razkritje"; +"Common.Controls.Status.Translation.ShowOriginal" = "Pokaži izvirnik"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Neznano"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ je poobjavil_a"; "Common.Controls.Status.UserRepliedTo" = "Odgovarja %@"; "Common.Controls.Status.Visibility.Direct" = "Samo omenjeni uporabnik lahko vidi to objavo."; @@ -131,9 +144,9 @@ Preverite svojo internetno povezavo."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Samo moji sledilci lahko vidijo to objavo."; "Common.Controls.Status.Visibility.Unlisted" = "Vsak lahko vidi to objavo, ni pa prikazana na javni časovnici."; "Common.Controls.Tabs.Home" = "Domov"; -"Common.Controls.Tabs.Notification" = "Obvestilo"; +"Common.Controls.Tabs.Notifications" = "Obvestila"; "Common.Controls.Tabs.Profile" = "Profil"; -"Common.Controls.Tabs.Search" = "Iskanje"; +"Common.Controls.Tabs.SearchAndExplore" = "Poišči in razišči"; "Common.Controls.Timeline.Filtered" = "Filtrirano"; "Common.Controls.Timeline.Header.BlockedWarning" = "Profila tega uporabnika ne morete videti, dokler vas ne odblokirajo."; @@ -229,6 +242,12 @@ možno naložiti v Mastodon."; "Scene.Familiarfollowers.Title" = "Znani sledilci"; "Scene.Favorite.Title" = "Vaši priljubljeni"; "Scene.FavoritedBy.Title" = "Med priljubljene dal_a"; +"Scene.FollowedTags.Actions.Follow" = "Sledi"; +"Scene.FollowedTags.Actions.Unfollow" = "Prenehaj slediti"; +"Scene.FollowedTags.Header.Participants" = "udeležencev"; +"Scene.FollowedTags.Header.Posts" = "objav"; +"Scene.FollowedTags.Header.PostsToday" = "objav danes"; +"Scene.FollowedTags.Title" = "Sledene značke"; "Scene.Follower.Footer" = "Sledilci z drugih strežnikov niso prikazani."; "Scene.Follower.Title" = "sledilec"; "Scene.Following.Footer" = "Sledenje z drugih strežnikov ni prikazano."; @@ -268,6 +287,7 @@ možno naložiti v Mastodon."; "Scene.Profile.Dashboard.Following" = "sledi"; "Scene.Profile.Dashboard.Posts" = "Objave"; "Scene.Profile.Fields.AddRow" = "Dodaj vrstico"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "Vsebina"; "Scene.Profile.Fields.Placeholder.Label" = "Oznaka"; "Scene.Profile.Fields.Verified.Long" = "Lastništvo te povezave je bilo preverjeno %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/sv.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/sv.lproj/Localizable.strings index 79781cae7..4da00cad1 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/sv.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/sv.lproj/Localizable.strings @@ -22,6 +22,9 @@ Kontrollera din internetanslutning."; "Common.Alerts.SignOut.Message" = "Är du säker på att du vill logga ut?"; "Common.Alerts.SignOut.Title" = "Logga ut"; "Common.Alerts.SignUpFailure.Title" = "Registrering misslyckades"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Översättningen misslyckades. Det kan hända att administratören inte har aktiverat översättningar på den här servern eller att servern kör en äldre version av Mastodon som inte har stöd för översättningar ännu."; +"Common.Alerts.TranslationFailed.Title" = "Anteckning"; "Common.Alerts.VoteFailure.PollEnded" = "Omröstningen har avslutats"; "Common.Alerts.VoteFailure.Title" = "Röstning misslyckades"; "Common.Controls.Actions.Add" = "Lägg till"; @@ -31,6 +34,7 @@ Kontrollera din internetanslutning."; "Common.Controls.Actions.Compose" = "Skriv"; "Common.Controls.Actions.Confirm" = "Bekräfta"; "Common.Controls.Actions.Continue" = "Fortsätt"; +"Common.Controls.Actions.Copy" = "Kopiera"; "Common.Controls.Actions.CopyPhoto" = "Kopiera foto"; "Common.Controls.Actions.Delete" = "Radera"; "Common.Controls.Actions.Discard" = "Släng"; @@ -59,6 +63,8 @@ Kontrollera din internetanslutning."; "Common.Controls.Actions.SignUp" = "Skapa konto"; "Common.Controls.Actions.Skip" = "Hoppa över"; "Common.Controls.Actions.TakePhoto" = "Ta foto"; +"Common.Controls.Actions.TranslatePost.Title" = "Översätt från %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Okänt"; "Common.Controls.Actions.TryAgain" = "Försök igen"; "Common.Controls.Actions.UnblockDomain" = "Avblockera %@"; "Common.Controls.Friendship.Block" = "Blockera"; @@ -100,6 +106,7 @@ Kontrollera din internetanslutning."; "Common.Controls.Status.Actions.Menu" = "Meny"; "Common.Controls.Status.Actions.Reblog" = "Boosta"; "Common.Controls.Status.Actions.Reply" = "Svara"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Dela länk i inlägg"; "Common.Controls.Status.Actions.ShowGif" = "Visa GIF"; "Common.Controls.Status.Actions.ShowImage" = "Visa bild"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Visa videospelare"; @@ -107,6 +114,8 @@ Kontrollera din internetanslutning."; "Common.Controls.Status.Actions.Unfavorite" = "Ta bort favorit"; "Common.Controls.Status.Actions.Unreblog" = "Ångra boost"; "Common.Controls.Status.ContentWarning" = "Innehållsvarning"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Ladda inbäddning"; "Common.Controls.Status.MediaContentWarning" = "Tryck var som helst för att visa"; "Common.Controls.Status.MetaEntity.Email" = "E-postadress: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; @@ -124,6 +133,10 @@ Kontrollera din internetanslutning."; "Common.Controls.Status.Tag.Mention" = "Omnämn"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Tryck för att visa"; +"Common.Controls.Status.Translation.ShowOriginal" = "Visa original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Okänt"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ boostade"; "Common.Controls.Status.UserRepliedTo" = "Svarade på %@"; "Common.Controls.Status.Visibility.Direct" = "Endast omnämnda användare kan se detta inlägg."; @@ -131,9 +144,9 @@ Kontrollera din internetanslutning."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Bara mina följare kan se det här inlägget."; "Common.Controls.Status.Visibility.Unlisted" = "Alla kan se detta inlägg men det visas inte i den offentliga tidslinjen."; "Common.Controls.Tabs.Home" = "Hem"; -"Common.Controls.Tabs.Notification" = "Notis"; +"Common.Controls.Tabs.Notifications" = "Notiser"; "Common.Controls.Tabs.Profile" = "Profil"; -"Common.Controls.Tabs.Search" = "Sök"; +"Common.Controls.Tabs.SearchAndExplore" = "Sök och utforska"; "Common.Controls.Timeline.Filtered" = "Filtrerat"; "Common.Controls.Timeline.Header.BlockedWarning" = "Du kan inte visa den här användarens profil förrän de avblockerar dig."; @@ -229,6 +242,12 @@ laddas upp till Mastodon."; "Scene.Familiarfollowers.Title" = "Följare du liknar"; "Scene.Favorite.Title" = "Dina favoriter"; "Scene.FavoritedBy.Title" = "Favoriserad av"; +"Scene.FollowedTags.Actions.Follow" = "Följ"; +"Scene.FollowedTags.Actions.Unfollow" = "Avfölj"; +"Scene.FollowedTags.Header.Participants" = "deltagare"; +"Scene.FollowedTags.Header.Posts" = "inlägg"; +"Scene.FollowedTags.Header.PostsToday" = "inlägg idag"; +"Scene.FollowedTags.Title" = "Följda hashtaggar"; "Scene.Follower.Footer" = "Följare från andra servrar visas inte."; "Scene.Follower.Title" = "följare"; "Scene.Following.Footer" = "Följda på andra servrar visas inte."; @@ -268,6 +287,7 @@ laddas upp till Mastodon."; "Scene.Profile.Dashboard.Following" = "följer"; "Scene.Profile.Dashboard.Posts" = "inlägg"; "Scene.Profile.Fields.AddRow" = "Lägg till rad"; +"Scene.Profile.Fields.Joined" = "Gick med"; "Scene.Profile.Fields.Placeholder.Content" = "Innehåll"; "Scene.Profile.Fields.Placeholder.Label" = "Etikett"; "Scene.Profile.Fields.Verified.Long" = "Ägarskap för denna länk kontrollerades den %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/sv.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/sv.lproj/Localizable.stringsdict index 3cbfeae6d..43a0ff8e4 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/sv.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/sv.lproj/Localizable.stringsdict @@ -280,7 +280,7 @@ NSStringFormatValueTypeKey ld one - %ld år kvar + 1 år kvar other %ld år kvar @@ -296,7 +296,7 @@ NSStringFormatValueTypeKey ld one - %ld månad kvar + 1 månad kvar other %ld månader kvar @@ -312,7 +312,7 @@ NSStringFormatValueTypeKey ld one - %ld dag kvar + 1 dag kvar other %ld dagar kvar @@ -360,7 +360,7 @@ NSStringFormatValueTypeKey ld one - %ld sekund kvar + 1 sekund kvar other %ld sekunder kvar @@ -408,7 +408,7 @@ NSStringFormatValueTypeKey ld one - %ldd sedan + 1d sedan other %ldd sedan @@ -424,7 +424,7 @@ NSStringFormatValueTypeKey ld one - %ldt sedan + 1t sedan other %ldt sedan diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings index 25c7e37f8..6aeeb2a74 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings @@ -22,6 +22,9 @@ "Common.Alerts.SignOut.Message" = "คุณแน่ใจหรือไม่ว่าต้องการลงชื่อออก?"; "Common.Alerts.SignOut.Title" = "ลงชื่อออก"; "Common.Alerts.SignUpFailure.Title" = "การลงทะเบียนล้มเหลว"; +"Common.Alerts.TranslationFailed.Button" = "ตกลง"; +"Common.Alerts.TranslationFailed.Message" = "การแปลล้มเหลว บางทีผู้ดูแลอาจไม่ได้เปิดใช้งานการแปลในเซิร์ฟเวอร์นี้หรือเซิร์ฟเวอร์นี้กำลังใช้ Mastodon รุ่นเก่ากว่าที่ยังไม่รองรับการแปล"; +"Common.Alerts.TranslationFailed.Title" = "หมายเหตุ"; "Common.Alerts.VoteFailure.PollEnded" = "การสำรวจความคิดเห็นได้สิ้นสุดแล้ว"; "Common.Alerts.VoteFailure.Title" = "การลงคะแนนล้มเหลว"; "Common.Controls.Actions.Add" = "เพิ่ม"; @@ -31,6 +34,7 @@ "Common.Controls.Actions.Compose" = "เขียน"; "Common.Controls.Actions.Confirm" = "ยืนยัน"; "Common.Controls.Actions.Continue" = "ดำเนินการต่อ"; +"Common.Controls.Actions.Copy" = "คัดลอก"; "Common.Controls.Actions.CopyPhoto" = "คัดลอกรูปภาพ"; "Common.Controls.Actions.Delete" = "ลบ"; "Common.Controls.Actions.Discard" = "ละทิ้ง"; @@ -59,6 +63,8 @@ "Common.Controls.Actions.SignUp" = "สร้างบัญชี"; "Common.Controls.Actions.Skip" = "ข้าม"; "Common.Controls.Actions.TakePhoto" = "ถ่ายรูป"; +"Common.Controls.Actions.TranslatePost.Title" = "แปลจาก %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "ไม่รู้จัก"; "Common.Controls.Actions.TryAgain" = "ลองอีกครั้ง"; "Common.Controls.Actions.UnblockDomain" = "เลิกปิดกั้น %@"; "Common.Controls.Friendship.Block" = "ปิดกั้น"; @@ -100,6 +106,7 @@ "Common.Controls.Status.Actions.Menu" = "เมนู"; "Common.Controls.Status.Actions.Reblog" = "ดัน"; "Common.Controls.Status.Actions.Reply" = "ตอบกลับ"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "แบ่งปันลิงก์ในโพสต์"; "Common.Controls.Status.Actions.ShowGif" = "แสดง GIF"; "Common.Controls.Status.Actions.ShowImage" = "แสดงภาพ"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "แสดงตัวเล่นวิดีโอ"; @@ -107,6 +114,8 @@ "Common.Controls.Status.Actions.Unfavorite" = "เลิกชื่นชอบ"; "Common.Controls.Status.Actions.Unreblog" = "เลิกทำการดัน"; "Common.Controls.Status.ContentWarning" = "คำเตือนเนื้อหา"; +"Common.Controls.Status.LinkViaUser" = "%@ ผ่าน %@"; +"Common.Controls.Status.LoadEmbed" = "โหลดที่ฝังไว้"; "Common.Controls.Status.MediaContentWarning" = "แตะที่ใดก็ตามเพื่อเปิดเผย"; "Common.Controls.Status.MetaEntity.Email" = "ที่อยู่อีเมล: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "แฮชแท็ก: %@"; @@ -124,6 +133,10 @@ "Common.Controls.Status.Tag.Mention" = "กล่าวถึง"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "แตะเพื่อเปิดเผย"; +"Common.Controls.Status.Translation.ShowOriginal" = "แสดงดั้งเดิมอยู่"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "ไม่รู้จัก"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ ได้ดัน"; "Common.Controls.Status.UserRepliedTo" = "ตอบกลับ %@"; "Common.Controls.Status.Visibility.Direct" = "เฉพาะผู้ใช้ที่กล่าวถึงเท่านั้นที่สามารถเห็นโพสต์นี้"; @@ -131,9 +144,9 @@ "Common.Controls.Status.Visibility.PrivateFromMe" = "เฉพาะผู้ติดตามของฉันเท่านั้นที่สามารถเห็นโพสต์นี้"; "Common.Controls.Status.Visibility.Unlisted" = "ทุกคนสามารถเห็นโพสต์นี้แต่ไม่แสดงในเส้นเวลาสาธารณะ"; "Common.Controls.Tabs.Home" = "หน้าแรก"; -"Common.Controls.Tabs.Notification" = "การแจ้งเตือน"; +"Common.Controls.Tabs.Notifications" = "การแจ้งเตือน"; "Common.Controls.Tabs.Profile" = "โปรไฟล์"; -"Common.Controls.Tabs.Search" = "ค้นหา"; +"Common.Controls.Tabs.SearchAndExplore" = "ค้นหาและสำรวจ"; "Common.Controls.Timeline.Filtered" = "กรองอยู่"; "Common.Controls.Timeline.Header.BlockedWarning" = "คุณไม่สามารถดูโปรไฟล์ของผู้ใช้นี้ จนกว่าเขาจะเลิกปิดกั้นคุณ"; @@ -229,6 +242,12 @@ "Scene.Familiarfollowers.Title" = "ผู้ติดตามที่คุณคุ้นเคย"; "Scene.Favorite.Title" = "รายการโปรดของคุณ"; "Scene.FavoritedBy.Title" = "ชื่นชอบโดย"; +"Scene.FollowedTags.Actions.Follow" = "ติดตาม"; +"Scene.FollowedTags.Actions.Unfollow" = "เลิกติดตาม"; +"Scene.FollowedTags.Header.Participants" = "ผู้เข้าร่วม"; +"Scene.FollowedTags.Header.Posts" = "โพสต์"; +"Scene.FollowedTags.Header.PostsToday" = "โพสต์วันนี้"; +"Scene.FollowedTags.Title" = "แท็กที่ติดตาม"; "Scene.Follower.Footer" = "ไม่ได้แสดงผู้ติดตามจากเซิร์ฟเวอร์อื่น ๆ"; "Scene.Follower.Title" = "ผู้ติดตาม"; "Scene.Following.Footer" = "ไม่ได้แสดงการติดตามจากเซิร์ฟเวอร์อื่น ๆ"; @@ -268,6 +287,7 @@ "Scene.Profile.Dashboard.Following" = "กำลังติดตาม"; "Scene.Profile.Dashboard.Posts" = "โพสต์"; "Scene.Profile.Fields.AddRow" = "เพิ่มแถว"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "เนื้อหา"; "Scene.Profile.Fields.Placeholder.Label" = "ป้ายชื่อ"; "Scene.Profile.Fields.Verified.Long" = "ตรวจสอบความเป็นเจ้าของของลิงก์นี้เมื่อ %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings index fcee4e12e..c71fb332e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings @@ -21,6 +21,9 @@ "Common.Alerts.SignOut.Message" = "Oturumu kapatmak istediğinize emin misiniz?"; "Common.Alerts.SignOut.Title" = "Oturumu Kapat"; "Common.Alerts.SignUpFailure.Title" = "Kaydolma Başarısız"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "Anket bitti"; "Common.Alerts.VoteFailure.Title" = "Oy Verme Başarısız"; "Common.Controls.Actions.Add" = "Ekle"; @@ -30,6 +33,7 @@ "Common.Controls.Actions.Compose" = "Yaz"; "Common.Controls.Actions.Confirm" = "Onayla"; "Common.Controls.Actions.Continue" = "Devam et"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "Fotoğrafı Kopyala"; "Common.Controls.Actions.Delete" = "Sil"; "Common.Controls.Actions.Discard" = "Vazgeç"; @@ -54,10 +58,12 @@ "Common.Controls.Actions.Share" = "Paylaş"; "Common.Controls.Actions.SharePost" = "Gönderiyi Paylaş"; "Common.Controls.Actions.ShareUser" = "%@ ile paylaş"; -"Common.Controls.Actions.SignIn" = "Log in"; -"Common.Controls.Actions.SignUp" = "Create account"; +"Common.Controls.Actions.SignIn" = "Giriş Yap"; +"Common.Controls.Actions.SignUp" = "Hesap oluştur"; "Common.Controls.Actions.Skip" = "Atla"; "Common.Controls.Actions.TakePhoto" = "Fotoğraf Çek"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "Tekrar Deneyin"; "Common.Controls.Actions.UnblockDomain" = "%@ kişisinin engelini kaldır"; "Common.Controls.Friendship.Block" = "Engelle"; @@ -67,13 +73,13 @@ "Common.Controls.Friendship.EditInfo" = "Bilgiyi Düzenle"; "Common.Controls.Friendship.Follow" = "Takip et"; "Common.Controls.Friendship.Following" = "Takip ediliyor"; -"Common.Controls.Friendship.HideReblogs" = "Hide Reblogs"; +"Common.Controls.Friendship.HideReblogs" = "Yeniden Paylaşımları Gizle"; "Common.Controls.Friendship.Mute" = "Sessize al"; "Common.Controls.Friendship.MuteUser" = "Sustur %@"; "Common.Controls.Friendship.Muted" = "Susturuldu"; "Common.Controls.Friendship.Pending" = "Bekliyor"; "Common.Controls.Friendship.Request" = "İstek"; -"Common.Controls.Friendship.ShowReblogs" = "Show Reblogs"; +"Common.Controls.Friendship.ShowReblogs" = "Yeniden Paylaşımları Göster"; "Common.Controls.Friendship.Unblock" = "Engeli kaldır"; "Common.Controls.Friendship.UnblockUser" = "%@ kişisinin engelini kaldır"; "Common.Controls.Friendship.Unmute" = "Susturmayı kaldır"; @@ -99,6 +105,7 @@ "Common.Controls.Status.Actions.Menu" = "Menü"; "Common.Controls.Status.Actions.Reblog" = "Yeniden paylaş"; "Common.Controls.Status.Actions.Reply" = "Yanıtla"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "GIF'i göster"; "Common.Controls.Status.Actions.ShowImage" = "Görüntüyü göster"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Video oynatıcıyı göster"; @@ -106,11 +113,13 @@ "Common.Controls.Status.Actions.Unfavorite" = "Favorilerden Çıkar"; "Common.Controls.Status.Actions.Unreblog" = "Yeniden paylaşımı geri al"; "Common.Controls.Status.ContentWarning" = "İçerik Uyarısı"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "Göstermek için herhangi bir yere basın"; -"Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; -"Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; -"Common.Controls.Status.MetaEntity.Mention" = "Show Profile: %@"; -"Common.Controls.Status.MetaEntity.Url" = "Link: %@"; +"Common.Controls.Status.MetaEntity.Email" = "E-posta adresi: %@"; +"Common.Controls.Status.MetaEntity.Hashtag" = "Etiket: %@"; +"Common.Controls.Status.MetaEntity.Mention" = "Profili Göster: %@"; +"Common.Controls.Status.MetaEntity.Url" = "Bağlantı: %@"; "Common.Controls.Status.Poll.Closed" = "Kapandı"; "Common.Controls.Status.Poll.Vote" = "Oy ver"; "Common.Controls.Status.SensitiveContent" = "Hassas İçerik"; @@ -123,6 +132,10 @@ "Common.Controls.Status.Tag.Mention" = "Bahset"; "Common.Controls.Status.Tag.Url" = "Bağlantı"; "Common.Controls.Status.TapToReveal" = "Göstermek için basın"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ yeniden paylaştı"; "Common.Controls.Status.UserRepliedTo" = "%@ kullanıcısına yanıt verdi"; "Common.Controls.Status.Visibility.Direct" = "Sadece bahsedilen kullanıcı bu gönderiyi görebilir."; @@ -130,9 +143,9 @@ "Common.Controls.Status.Visibility.PrivateFromMe" = "Sadece benim takipçilerim bu gönderiyi görebilir."; "Common.Controls.Status.Visibility.Unlisted" = "Bu gönderiyi herkes görebilir, fakat herkese açık zaman tünelinde gösterilmez."; "Common.Controls.Tabs.Home" = "Ana Sayfa"; -"Common.Controls.Tabs.Notification" = "Bildirimler"; +"Common.Controls.Tabs.Notifications" = "Bildirimler"; "Common.Controls.Tabs.Profile" = "Profil"; -"Common.Controls.Tabs.Search" = "Arama"; +"Common.Controls.Tabs.SearchAndExplore" = "Ara ve Keşfet"; "Common.Controls.Timeline.Filtered" = "Filtrelenmiş"; "Common.Controls.Timeline.Header.BlockedWarning" = "Bu kişi sizin engelinizi kaldırana kadar onun profilini göremezsiniz."; @@ -154,27 +167,27 @@ Bu kişiye göre profiliniz böyle gözüküyor."; "Scene.AccountList.AddAccount" = "Hesap Ekle"; "Scene.AccountList.DismissAccountSwitcher" = "Hesap Değiştiriciyi Kapat"; "Scene.AccountList.TabBarHint" = "Şu anki seçili profil: %@. Hesap değiştiriciyi göstermek için iki kez dokunun ve basılı tutun"; -"Scene.Bookmark.Title" = "Bookmarks"; +"Scene.Bookmark.Title" = "Yer İmleri"; "Scene.Compose.Accessibility.AppendAttachment" = "Dosya Ekle"; "Scene.Compose.Accessibility.AppendPoll" = "Anket Ekle"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Özel Emoji Seçici"; "Scene.Compose.Accessibility.DisableContentWarning" = "İçerik Uyarısını Kapat"; "Scene.Compose.Accessibility.EnableContentWarning" = "İçerik Uyarısını Etkinleştir"; -"Scene.Compose.Accessibility.PostOptions" = "Post Options"; +"Scene.Compose.Accessibility.PostOptions" = "Gönderi Seçenekleri"; "Scene.Compose.Accessibility.PostVisibilityMenu" = "Gönderi Görünürlüğü Menüsü"; -"Scene.Compose.Accessibility.PostingAs" = "Posting as %@"; +"Scene.Compose.Accessibility.PostingAs" = "%@ olarak paylaşılıyor"; "Scene.Compose.Accessibility.RemovePoll" = "Anketi Kaldır"; "Scene.Compose.Attachment.AttachmentBroken" = "Bu %@ bozuk ve Mastodon'a yüklenemiyor."; -"Scene.Compose.Attachment.AttachmentTooLarge" = "Attachment too large"; -"Scene.Compose.Attachment.CanNotRecognizeThisMediaAttachment" = "Can not recognize this media attachment"; -"Scene.Compose.Attachment.CompressingState" = "Compressing..."; +"Scene.Compose.Attachment.AttachmentTooLarge" = "Ek boyutu çok büyük"; +"Scene.Compose.Attachment.CanNotRecognizeThisMediaAttachment" = "Ekteki medya uzantısı görüntülenemiyor"; +"Scene.Compose.Attachment.CompressingState" = "Sıkıştırılıyor..."; "Scene.Compose.Attachment.DescriptionPhoto" = "Görme engelliler için fotoğrafı tarif edin..."; "Scene.Compose.Attachment.DescriptionVideo" = "Görme engelliler için videoyu tarif edin..."; -"Scene.Compose.Attachment.LoadFailed" = "Load Failed"; +"Scene.Compose.Attachment.LoadFailed" = "Yükleme Başarısız"; "Scene.Compose.Attachment.Photo" = "fotoğraf"; -"Scene.Compose.Attachment.ServerProcessingState" = "Server Processing..."; -"Scene.Compose.Attachment.UploadFailed" = "Upload Failed"; +"Scene.Compose.Attachment.ServerProcessingState" = "Sunucu İşliyor..."; +"Scene.Compose.Attachment.UploadFailed" = "Yükleme Başarısız"; "Scene.Compose.Attachment.Video" = "video"; "Scene.Compose.AutoComplete.SpaceToAdd" = "Eklemek için boşluk tuşuna basın"; "Scene.Compose.ComposeAction" = "Yayınla"; @@ -196,7 +209,7 @@ yüklenemiyor."; "Scene.Compose.Poll.SevenDays" = "7 Gün"; "Scene.Compose.Poll.SixHours" = "6 Saat"; "Scene.Compose.Poll.ThePollHasEmptyOption" = "The poll has empty option"; -"Scene.Compose.Poll.ThePollIsInvalid" = "The poll is invalid"; +"Scene.Compose.Poll.ThePollIsInvalid" = "Anket geçersiz"; "Scene.Compose.Poll.ThirtyMinutes" = "30 dakika"; "Scene.Compose.Poll.ThreeDays" = "3 Gün"; "Scene.Compose.ReplyingToUser" = "yanıtlanıyor: %@"; @@ -224,10 +237,16 @@ yüklenemiyor."; "Scene.Discovery.Tabs.Hashtags" = "Etiketler"; "Scene.Discovery.Tabs.News" = "Haberler"; "Scene.Discovery.Tabs.Posts" = "Gönderiler"; -"Scene.Familiarfollowers.FollowedByNames" = "Followed by %@"; -"Scene.Familiarfollowers.Title" = "Followers you familiar"; +"Scene.Familiarfollowers.FollowedByNames" = "%@ tarafından takip ediliyor"; +"Scene.Familiarfollowers.Title" = "Tanıyor olabileceğin takipçiler"; "Scene.Favorite.Title" = "Favorilerin"; "Scene.FavoritedBy.Title" = "Favorited By"; +"Scene.FollowedTags.Actions.Follow" = "Takip et"; +"Scene.FollowedTags.Actions.Unfollow" = "Takibi bırak"; +"Scene.FollowedTags.Header.Participants" = "katılımcılar"; +"Scene.FollowedTags.Header.Posts" = "gönderiler"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Takip Edilen Etiketler"; "Scene.Follower.Footer" = "Diğer sunucudaki takipçiler gösterilemiyor."; "Scene.Follower.Title" = "takipçi"; "Scene.Following.Footer" = "Diğer sunucudaki takip edilenler gösterilemiyor."; @@ -239,13 +258,13 @@ yüklenemiyor."; "Scene.HomeTimeline.NavigationBarState.Published" = "Yayınlandı!"; "Scene.HomeTimeline.NavigationBarState.Publishing" = "Gönderi yayınlanıyor..."; "Scene.HomeTimeline.Title" = "Ana Sayfa"; -"Scene.Login.ServerSearchField.Placeholder" = "Enter URL or search for your server"; -"Scene.Login.Subtitle" = "Log you in on the server you created your account on."; -"Scene.Login.Title" = "Welcome back"; -"Scene.Notification.FollowRequest.Accept" = "Accept"; -"Scene.Notification.FollowRequest.Accepted" = "Accepted"; -"Scene.Notification.FollowRequest.Reject" = "reject"; -"Scene.Notification.FollowRequest.Rejected" = "Rejected"; +"Scene.Login.ServerSearchField.Placeholder" = "Bir URL girin ya da sunucunuzu arayın"; +"Scene.Login.Subtitle" = "Hesabını oluşturduğun sunucuya giriş yap."; +"Scene.Login.Title" = "Tekrar hoş geldin"; +"Scene.Notification.FollowRequest.Accept" = "Kabul Et"; +"Scene.Notification.FollowRequest.Accepted" = "Kabul Edildi"; +"Scene.Notification.FollowRequest.Reject" = "Reddet"; +"Scene.Notification.FollowRequest.Rejected" = "Reddedildi"; "Scene.Notification.Keyobard.ShowEverything" = "Her Şeyi Göster"; "Scene.Notification.Keyobard.ShowMentions" = "Bahsetmeleri Göster"; "Scene.Notification.NotificationDescription.FavoritedYourPost" = "gönderini favoriledi"; @@ -267,19 +286,20 @@ yüklenemiyor."; "Scene.Profile.Dashboard.Following" = "takip ediliyor"; "Scene.Profile.Dashboard.Posts" = "gönderiler"; "Scene.Profile.Fields.AddRow" = "Satır Ekle"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "İçerik"; "Scene.Profile.Fields.Placeholder.Label" = "Etiket"; -"Scene.Profile.Fields.Verified.Long" = "Ownership of this link was checked on %@"; -"Scene.Profile.Fields.Verified.Short" = "Verified on %@"; +"Scene.Profile.Fields.Verified.Long" = "%@ adresinin sahipliği kontrol edilmiş"; +"Scene.Profile.Fields.Verified.Short" = "%@ tarafında onaylı"; "Scene.Profile.Header.FollowsYou" = "Seni takip ediyor"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "%@ engellemeyi onayla"; "Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Hesabı Engelle"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Confirm to hide reblogs"; -"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Hide Reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Message" = "Yeniden paylaşımları gizlemeyi onayla"; +"Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.Title" = "Yeniden Paylaşımları Gizle"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "%@ susturmak için onaylayın"; "Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Hesabı sustur"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Confirm to show reblogs"; -"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Show Reblogs"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Message" = "Yeniden paylaşımları göstermeyi onayla"; +"Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.Title" = "Yeniden Paylaşımları Göster"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "%@ engellemeyi kaldırmayı onaylayın"; "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Hesabın Engelini Kaldır"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "%@ susturmasını kaldırmak için onaylayın"; @@ -332,15 +352,15 @@ yüklenemiyor."; "Scene.Report.SkipToSend" = "Yorum yapmadan gönder"; "Scene.Report.Step1" = "Adım 1/2"; "Scene.Report.Step2" = "Adım 2/2"; -"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.BlockUser" = "%@ kişisini engelle"; "Scene.Report.StepFinal.DontWantToSeeThis" = "Bunu görmek istemiyor musunuz?"; "Scene.Report.StepFinal.MuteUser" = "Sustur %@"; -"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "Artık sizi takip edemez ve gönderilerinizi göremezler ama engellendiklerini görebilirler."; "Scene.Report.StepFinal.Unfollow" = "Takibi bırak"; "Scene.Report.StepFinal.UnfollowUser" = "Takipten çık %@"; -"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; -"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; -"Scene.Report.StepFinal.WhileWeReviewThisYouCanTakeActionAgainstUser" = "While we review this, you can take action against %@"; +"Scene.Report.StepFinal.Unfollowed" = "Takipten çıkıldı"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "Mastodon'da beğenmediğiniz bir şey gördüğünüzde, o kişiyi deneyiminizden çıkarabilirsiniz."; +"Scene.Report.StepFinal.WhileWeReviewThisYouCanTakeActionAgainstUser" = "Biz bunu incelerken siz %@ hesabına karşı önlem alabilirsiniz"; "Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; "Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Bilmemiz gereken başka bir şey var mı?"; "Scene.Report.StepFour.Step4Of4" = "Adım 4/4"; @@ -349,14 +369,14 @@ yüklenemiyor."; "Scene.Report.StepOne.ItViolatesServerRules" = "Sunucu kurallarını ihlal ediyor"; "Scene.Report.StepOne.ItsSomethingElse" = "Başka bir şey"; "Scene.Report.StepOne.ItsSpam" = "Spam"; -"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Kötü niyetli bağlantılar, sahte etkileşim veya tekrarlayan yanıtlar"; "Scene.Report.StepOne.SelectTheBestMatch" = "En iyi seçeneceği seçiniz"; "Scene.Report.StepOne.Step1Of4" = "Adım 1/4"; "Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "Sorun bunlardan biri değil"; "Scene.Report.StepOne.WhatsWrongWithThisAccount" = "Bu hesap ile ilgili sorun nedir?"; "Scene.Report.StepOne.WhatsWrongWithThisPost" = "Bu gönderi ile ilgili sorun nedir?"; "Scene.Report.StepOne.WhatsWrongWithThisUsername" = "%@ kişisinin sorunu nedir?"; -"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "Belirli kuralları ihlal ettiğinin farkındasınız"; "Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Bu bildirimi destekleyecek herhangi bir gönderi var mı?"; "Scene.Report.StepThree.SelectAllThatApply" = "Geçerli olanların tümünü seçiniz"; "Scene.Report.StepThree.Step3Of4" = "Adım 3/4"; @@ -403,11 +423,11 @@ yüklenemiyor."; "Scene.ServerPicker.EmptyState.BadNetwork" = "Veriyi yüklerken bir hata oluştu. Lütfen internet bağlantınızı kontrol edin."; "Scene.ServerPicker.EmptyState.FindingServers" = "Mevcut sunucular aranıyor..."; "Scene.ServerPicker.EmptyState.NoResults" = "Sonuç yok"; -"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Topluluklar arayın ya da bir URL girin"; "Scene.ServerPicker.Label.Category" = "KATEGORİ"; "Scene.ServerPicker.Label.Language" = "DİL"; "Scene.ServerPicker.Label.Users" = "KULLANICILAR"; -"Scene.ServerPicker.Subtitle" = "Pick a server based on your region, interests, or a general purpose one. You can still chat with anyone on Mastodon, regardless of your servers."; +"Scene.ServerPicker.Subtitle" = "Bölgenize dayalı, ilginize dayalı ya da genel amaçlı bir sunucu seçin. Hangi sunucuda olduğunuz fark etmeksizin Mastodon'daki herkes ile konuşabilirsiniz."; "Scene.ServerPicker.Title" = "Mastodon, farklı topluluklardaki kullanıcılardan oluşur."; "Scene.ServerRules.Button.Confirm" = "Kabul Ediyorum"; "Scene.ServerRules.PrivacyPolicy" = "gizlilik politikası"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.stringsdict index 6ef7f4c75..13552b607 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.stringsdict @@ -53,7 +53,7 @@ a11y.plural.count.characters_left NSStringLocalizedFormatKey - %#@character_count@ left + %#@character_count@ kaldı character_count NSStringFormatSpecTypeKey @@ -61,9 +61,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 karakter other - %ld characters + %ld karakter plural.count.followed_by_and_mutual @@ -88,9 +88,9 @@ NSStringFormatValueTypeKey ld one - Followed by %1$@, and another mutual + %1$@ ve bir ortak kişi tarafından takip edildi other - Followed by %1$@, and %ld mutuals + %1$@ ve %ld ortak kişi tarafından takip edildi plural.count.metric_formatted.post @@ -120,9 +120,9 @@ NSStringFormatValueTypeKey ld one - 1 media + 1 medya other - %ld media + %ld medya plural.count.post diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings index 5a14fb2cf..dc66003cc 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings @@ -22,6 +22,9 @@ Vui lòng kiểm tra kết nối mạng."; "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.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Dịch không thành công. Có thể quản trị viên chưa bật dịch trên máy chủ này hoặc máy chủ này đang chạy phiên bản cũ hơn của Mastodon chưa hỗ trợ dịch."; +"Common.Alerts.TranslationFailed.Title" = "Ghi chú"; "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"; @@ -31,6 +34,7 @@ Vui lòng kiểm tra kết nối mạng."; "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.Copy" = "Chép"; "Common.Controls.Actions.CopyPhoto" = "Sao chép ảnh"; "Common.Controls.Actions.Delete" = "Xóa"; "Common.Controls.Actions.Discard" = "Bỏ qua"; @@ -59,6 +63,8 @@ Vui lòng kiểm tra kết nối mạng."; "Common.Controls.Actions.SignUp" = "Tạo tài khoản"; "Common.Controls.Actions.Skip" = "Bỏ qua"; "Common.Controls.Actions.TakePhoto" = "Chụp ảnh"; +"Common.Controls.Actions.TranslatePost.Title" = "Dịch từ %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Chưa xác định"; "Common.Controls.Actions.TryAgain" = "Thử lại"; "Common.Controls.Actions.UnblockDomain" = "Bỏ chặn %@"; "Common.Controls.Friendship.Block" = "Chặn"; @@ -100,6 +106,7 @@ Vui lòng kiểm tra kết nối mạng."; "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.ShareLinkInPost" = "Chia sẻ liên kết trong Tút"; "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"; @@ -107,6 +114,8 @@ Vui lòng kiểm tra kết nối mạng."; "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.LinkViaUser" = "%@ bởi %@"; +"Common.Controls.Status.LoadEmbed" = "Nạp mã nhúng"; "Common.Controls.Status.MediaContentWarning" = "Nhấn để hiển thị"; "Common.Controls.Status.MetaEntity.Email" = "Email: %@"; "Common.Controls.Status.MetaEntity.Hashtag" = "Hashtag: %@"; @@ -124,6 +133,10 @@ Vui lòng kiểm tra kết nối mạng."; "Common.Controls.Status.Tag.Mention" = "Nhắc đến"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Nhấn để xem"; +"Common.Controls.Status.Translation.ShowOriginal" = "Bản gốc"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Không xác định"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ đăng lại"; "Common.Controls.Status.UserRepliedTo" = "Trả lời đến %@"; "Common.Controls.Status.Visibility.Direct" = "Chỉ người được nhắc đến có thể thấy tút."; @@ -131,9 +144,9 @@ Vui lòng kiểm tra kết nối mạng."; "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.Notifications" = "Thông báo"; "Common.Controls.Tabs.Profile" = "Trang hồ sơ"; -"Common.Controls.Tabs.Search" = "Tìm kiếm"; +"Common.Controls.Tabs.SearchAndExplore" = "Tìm và Khám Phá"; "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."; @@ -200,7 +213,7 @@ tải lên Mastodon."; "Scene.Compose.Poll.ThePollIsInvalid" = "Bình chọn không hợp lệ"; "Scene.Compose.Poll.ThirtyMinutes" = "30 phút"; "Scene.Compose.Poll.ThreeDays" = "3 ngày"; -"Scene.Compose.ReplyingToUser" = "trả lời %@"; +"Scene.Compose.ReplyingToUser" = "%@ viết tiếp"; "Scene.Compose.Title.NewPost" = "Viết tút"; "Scene.Compose.Title.NewReply" = "Viết trả lời"; "Scene.Compose.Visibility.Direct" = "Nhắn riêng"; @@ -229,6 +242,12 @@ tải lên Mastodon."; "Scene.Familiarfollowers.Title" = "Người theo dõi tương tự"; "Scene.Favorite.Title" = "Lượt thích"; "Scene.FavoritedBy.Title" = "Thích bởi"; +"Scene.FollowedTags.Actions.Follow" = "Theo dõi"; +"Scene.FollowedTags.Actions.Unfollow" = "Ngưng theo dõi"; +"Scene.FollowedTags.Header.Participants" = "người thảo luận"; +"Scene.FollowedTags.Header.Posts" = "tút"; +"Scene.FollowedTags.Header.PostsToday" = "tút hôm nay"; +"Scene.FollowedTags.Title" = "Hashtag Theo Dõi"; "Scene.Follower.Footer" = "Không hiển thị người theo dõi từ máy chủ khác."; "Scene.Follower.Title" = "người theo dõi"; "Scene.Following.Footer" = "Không hiển thị người bạn theo dõi từ máy chủ khác."; @@ -268,6 +287,7 @@ tải lên Mastodon."; "Scene.Profile.Dashboard.Following" = "theo dõi"; "Scene.Profile.Dashboard.Posts" = "tút"; "Scene.Profile.Fields.AddRow" = "Thêm hàng"; +"Scene.Profile.Fields.Joined" = "Đã tham gia"; "Scene.Profile.Fields.Placeholder.Content" = "Nội dung"; "Scene.Profile.Fields.Placeholder.Label" = "Nhãn"; "Scene.Profile.Fields.Verified.Long" = "Liên kết này đã được xác minh trên %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings index 0c779d293..7d164f80e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings @@ -22,6 +22,9 @@ "Common.Alerts.SignOut.Message" = "您确定要退出吗?"; "Common.Alerts.SignOut.Title" = "退出"; "Common.Alerts.SignUpFailure.Title" = "注册失败"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "Translation failed. Maybe the administrator has not enabled translations on this server or this server is running an older version of Mastodon where translations are not yet supported."; +"Common.Alerts.TranslationFailed.Title" = "Note"; "Common.Alerts.VoteFailure.PollEnded" = "投票已结束"; "Common.Alerts.VoteFailure.Title" = "投票失败"; "Common.Controls.Actions.Add" = "添加"; @@ -31,6 +34,7 @@ "Common.Controls.Actions.Compose" = "撰写"; "Common.Controls.Actions.Confirm" = "确认"; "Common.Controls.Actions.Continue" = "继续"; +"Common.Controls.Actions.Copy" = "Copy"; "Common.Controls.Actions.CopyPhoto" = "拷贝照片"; "Common.Controls.Actions.Delete" = "删除"; "Common.Controls.Actions.Discard" = "放弃"; @@ -59,6 +63,8 @@ "Common.Controls.Actions.SignUp" = "创建账户"; "Common.Controls.Actions.Skip" = "跳过"; "Common.Controls.Actions.TakePhoto" = "拍照"; +"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown"; "Common.Controls.Actions.TryAgain" = "再试一次"; "Common.Controls.Actions.UnblockDomain" = "解除屏蔽 %@"; "Common.Controls.Friendship.Block" = "屏蔽"; @@ -100,6 +106,7 @@ "Common.Controls.Status.Actions.Menu" = "菜单"; "Common.Controls.Status.Actions.Reblog" = "转发"; "Common.Controls.Status.Actions.Reply" = "回复"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "Share Link in Post"; "Common.Controls.Status.Actions.ShowGif" = "显示 GIF"; "Common.Controls.Status.Actions.ShowImage" = "显示图片"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "显示视频播放器"; @@ -107,6 +114,8 @@ "Common.Controls.Status.Actions.Unfavorite" = "取消喜欢"; "Common.Controls.Status.Actions.Unreblog" = "取消转发"; "Common.Controls.Status.ContentWarning" = "内容警告"; +"Common.Controls.Status.LinkViaUser" = "%@ via %@"; +"Common.Controls.Status.LoadEmbed" = "Load Embed"; "Common.Controls.Status.MediaContentWarning" = "点击任意位置显示"; "Common.Controls.Status.MetaEntity.Email" = "邮箱地址:%@"; "Common.Controls.Status.MetaEntity.Hashtag" = "话题:%@"; @@ -124,6 +133,10 @@ "Common.Controls.Status.Tag.Mention" = "提及"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "点击以显示"; +"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ 转发"; "Common.Controls.Status.UserRepliedTo" = "回复给 %@"; "Common.Controls.Status.Visibility.Direct" = "只有提到的用户才能看到此帖子。"; @@ -131,9 +144,9 @@ "Common.Controls.Status.Visibility.PrivateFromMe" = "只有我的关注者才能看到此帖子。"; "Common.Controls.Status.Visibility.Unlisted" = "任何人都可以看到这个帖子,但不会在公开的时间线中显示。"; "Common.Controls.Tabs.Home" = "主页"; -"Common.Controls.Tabs.Notification" = "通知"; +"Common.Controls.Tabs.Notifications" = "通知"; "Common.Controls.Tabs.Profile" = "个人资料"; -"Common.Controls.Tabs.Search" = "搜索"; +"Common.Controls.Tabs.SearchAndExplore" = "Search and Explore"; "Common.Controls.Timeline.Filtered" = "已过滤"; "Common.Controls.Timeline.Header.BlockedWarning" = "您不能查看此用户的个人资料 直到他们解除屏蔽。"; @@ -229,6 +242,12 @@ "Scene.Familiarfollowers.Title" = "你熟悉的关注者"; "Scene.Favorite.Title" = "你的喜欢"; "Scene.FavoritedBy.Title" = "收藏者"; +"Scene.FollowedTags.Actions.Follow" = "Follow"; +"Scene.FollowedTags.Actions.Unfollow" = "Unfollow"; +"Scene.FollowedTags.Header.Participants" = "participants"; +"Scene.FollowedTags.Header.Posts" = "posts"; +"Scene.FollowedTags.Header.PostsToday" = "posts today"; +"Scene.FollowedTags.Title" = "Followed Tags"; "Scene.Follower.Footer" = "不会显示来自其它服务器的关注者"; "Scene.Follower.Title" = "关注者"; "Scene.Following.Footer" = "不会显示来自其它服务器的关注"; @@ -268,6 +287,7 @@ "Scene.Profile.Dashboard.Following" = "正在关注"; "Scene.Profile.Dashboard.Posts" = "帖子"; "Scene.Profile.Fields.AddRow" = "添加"; +"Scene.Profile.Fields.Joined" = "Joined"; "Scene.Profile.Fields.Placeholder.Content" = "内容"; "Scene.Profile.Fields.Placeholder.Label" = "标签"; "Scene.Profile.Fields.Verified.Long" = "此链接的所有权已在 %@ 上检查通过"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings index 10dbbf8ca..eba0703c7 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings @@ -22,6 +22,9 @@ "Common.Alerts.SignOut.Message" = "您確定要登出嗎?"; "Common.Alerts.SignOut.Title" = "登出"; "Common.Alerts.SignUpFailure.Title" = "註冊失敗"; +"Common.Alerts.TranslationFailed.Button" = "OK"; +"Common.Alerts.TranslationFailed.Message" = "翻譯失敗。也許管理員未於此伺服器啟用翻譯功能,或此伺服器為未支援翻譯功能之舊版本 Mastodon。"; +"Common.Alerts.TranslationFailed.Title" = "備註"; "Common.Alerts.VoteFailure.PollEnded" = "投票已結束"; "Common.Alerts.VoteFailure.Title" = "投票失敗"; "Common.Controls.Actions.Add" = "新增"; @@ -31,6 +34,7 @@ "Common.Controls.Actions.Compose" = "撰寫"; "Common.Controls.Actions.Confirm" = "確認"; "Common.Controls.Actions.Continue" = "繼續"; +"Common.Controls.Actions.Copy" = "複製"; "Common.Controls.Actions.CopyPhoto" = "複製照片"; "Common.Controls.Actions.Delete" = "刪除"; "Common.Controls.Actions.Discard" = "捨棄"; @@ -59,6 +63,8 @@ "Common.Controls.Actions.SignUp" = "新增帳號"; "Common.Controls.Actions.Skip" = "跳過"; "Common.Controls.Actions.TakePhoto" = "拍攝照片"; +"Common.Controls.Actions.TranslatePost.Title" = "翻譯自 %@"; +"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "未知"; "Common.Controls.Actions.TryAgain" = "再試一次"; "Common.Controls.Actions.UnblockDomain" = "解除封鎖 %@"; "Common.Controls.Friendship.Block" = "封鎖"; @@ -100,6 +106,7 @@ "Common.Controls.Status.Actions.Menu" = "選單"; "Common.Controls.Status.Actions.Reblog" = "轉嘟"; "Common.Controls.Status.Actions.Reply" = "回覆"; +"Common.Controls.Status.Actions.ShareLinkInPost" = "於嘟文中分享鏈結"; "Common.Controls.Status.Actions.ShowGif" = "顯示 GIF"; "Common.Controls.Status.Actions.ShowImage" = "顯示圖片"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "顯示影片播放器"; @@ -107,6 +114,8 @@ "Common.Controls.Status.Actions.Unfavorite" = "取消最愛"; "Common.Controls.Status.Actions.Unreblog" = "取消轉嘟"; "Common.Controls.Status.ContentWarning" = "內容警告"; +"Common.Controls.Status.LinkViaUser" = "%@ 透過 %@"; +"Common.Controls.Status.LoadEmbed" = "讀取嵌入內容"; "Common.Controls.Status.MediaContentWarning" = "輕觸任何地方以顯示"; "Common.Controls.Status.MetaEntity.Email" = "電子郵件地址:%@"; "Common.Controls.Status.MetaEntity.Hashtag" = "主題標籤: %@"; @@ -124,6 +133,10 @@ "Common.Controls.Status.Tag.Mention" = "提及"; "Common.Controls.Status.Tag.Url" = "網址"; "Common.Controls.Status.TapToReveal" = "輕觸以顯示"; +"Common.Controls.Status.Translation.ShowOriginal" = "顯示原文"; +"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; +"Common.Controls.Status.Translation.UnknownLanguage" = "未知"; +"Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; "Common.Controls.Status.UserReblogged" = "%@ 已轉嘟"; "Common.Controls.Status.UserRepliedTo" = "回覆給 %@"; "Common.Controls.Status.Visibility.Direct" = "只有被提及的使用者能看到此嘟文。"; @@ -131,9 +144,9 @@ "Common.Controls.Status.Visibility.PrivateFromMe" = "只有我的跟隨者能看到此嘟文。"; "Common.Controls.Status.Visibility.Unlisted" = "任何人都能看到此嘟文,但是不會顯示於公開時間軸上。"; "Common.Controls.Tabs.Home" = "首頁"; -"Common.Controls.Tabs.Notification" = "通知"; +"Common.Controls.Tabs.Notifications" = "通知"; "Common.Controls.Tabs.Profile" = "個人檔案"; -"Common.Controls.Tabs.Search" = "搜尋"; +"Common.Controls.Tabs.SearchAndExplore" = "搜尋與探索"; "Common.Controls.Timeline.Filtered" = "已過濾"; "Common.Controls.Timeline.Header.BlockedWarning" = "您無法瀏覽該使用者的個人檔案,除非他們取消封鎖您。"; "Common.Controls.Timeline.Header.BlockingWarning" = "您無法瀏覽該使用者的個人檔案,除非您取消封鎖。 @@ -224,6 +237,12 @@ "Scene.Familiarfollowers.Title" = "您熟悉的跟隨者"; "Scene.Favorite.Title" = "您的最愛"; "Scene.FavoritedBy.Title" = "已加入最愛"; +"Scene.FollowedTags.Actions.Follow" = "跟隨"; +"Scene.FollowedTags.Actions.Unfollow" = "取消跟隨"; +"Scene.FollowedTags.Header.Participants" = "參與者"; +"Scene.FollowedTags.Header.Posts" = "嘟文"; +"Scene.FollowedTags.Header.PostsToday" = "本日嘟文"; +"Scene.FollowedTags.Title" = "已跟隨主題標籤"; "Scene.Follower.Footer" = "來自其他伺服器的跟隨者不會被顯示。"; "Scene.Follower.Title" = "跟隨者"; "Scene.Following.Footer" = "來自其他伺服器的跟隨中不會被顯示。"; @@ -263,6 +282,7 @@ "Scene.Profile.Dashboard.Following" = "跟隨中"; "Scene.Profile.Dashboard.Posts" = "嘟文"; "Scene.Profile.Fields.AddRow" = "新增列"; +"Scene.Profile.Fields.Joined" = "加入時間"; "Scene.Profile.Fields.Placeholder.Content" = "內容"; "Scene.Profile.Fields.Placeholder.Label" = "標籤"; "Scene.Profile.Fields.Verified.Long" = "已在 %@ 檢查此連結的擁有者權限"; diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+FollowedTags.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+FollowedTags.swift new file mode 100644 index 000000000..02c79e35b --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+FollowedTags.swift @@ -0,0 +1,73 @@ +// +// Mastodon+API+Account+FollowedTags.swift +// +// +// Created by Marcus Kida on 22.11.22. +// + +import Foundation +import Combine + +extension Mastodon.API.Account { + + static func followedTagsEndpointURL(domain: String) -> URL { + return Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("followed_tags") + } + + /// Followed Tags + /// + /// View your followed hashtags. + /// + /// - Since: 4.0.0 + /// - Version: 4.0.3 + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/followed_tags/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - authorization: User token + /// - Returns: `AnyPublisher` contains `[Tag]` nested in the response + public static func followedTags( + session: URLSession, + domain: String, + query: FollowedTagsQuery, + authorization: Mastodon.API.OAuth.Authorization + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: followedTagsEndpointURL(domain: domain), + query: query, + authorization: authorization + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: [Mastodon.Entity.Tag].self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + + public struct FollowedTagsQuery: Codable, GetQuery { + + public let limit: Int? // default 100 + + enum CodingKeys: String, CodingKey { + case limit + } + + public init( + limit: Int? + ) { + self.limit = limit + } + + var queryItems: [URLQueryItem]? { + var items: [URLQueryItem] = [] + limit.flatMap { items.append(URLQueryItem(name: "limit", value: String($0))) } + guard !items.isEmpty else { return nil } + return items + } + + } + +} diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Friendship.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Friendship.swift index 2c0c39b97..278e6cd27 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Friendship.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Account+Friendship.swift @@ -215,6 +215,70 @@ extension Mastodon.API.Account { } +public extension Mastodon.API.Account { + + static func blocksEndpointURL(domain: String) -> URL { + return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("blocks") + } + + /// Block + /// + /// Block the given account. Clients should filter statuses from this account if received (e.g. due to a boost in the Home timeline). + /// + /// - Since: 0.0.0 + /// - Version: 3.3.0 + /// # Last Update + /// 2021/4/1 + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/blocks/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - authorization: User token. + /// - Returns: `AnyPublisher` contains `Relationship` nested in the response + static func blocks( + session: URLSession, + domain: String, + sinceID: Mastodon.Entity.Status.ID?, + limit: Int?, + authorization: Mastodon.API.OAuth.Authorization + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: blocksEndpointURL(domain: domain), + query: BlocksQuery(sinceID: sinceID, limit: limit), + authorization: authorization + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: [Mastodon.Entity.Account].self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + + private struct BlocksQuery: GetQuery { + private let sinceID: Mastodon.Entity.Status.ID? + private let limit: Int? + + public init( + sinceID: Mastodon.Entity.Status.ID?, + limit: Int? + ) { + self.sinceID = sinceID + self.limit = limit + } + + var queryItems: [URLQueryItem]? { + var items: [URLQueryItem] = [] + sinceID.flatMap { items.append(URLQueryItem(name: "since_id", value: $0)) } + limit.flatMap { items.append(URLQueryItem(name: "limit", value: String($0))) } + guard !items.isEmpty else { return nil } + return items + } + } + +} + extension Mastodon.API.Account { static func blockEndpointURL(domain: String, accountID: Mastodon.Entity.Account.ID) -> URL { @@ -414,3 +478,70 @@ extension Mastodon.API.Account { } } + +extension Mastodon.API.Account { + + static func mutesEndpointURL( + domain: String + ) -> URL { + return Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("mutes") + } + + /// View all mutes + /// + /// View your mutes. See also accounts/:id/{mute,unmute}. + /// + /// - Since: 0.0.0 + /// - Version: 3.3.0 + /// # Last Update + /// 2021/4/1 + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/accounts/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - accountID: id for account + /// - authorization: User token. + /// - Returns: `AnyPublisher` contains `Relationship` nested in the response + public static func mutes( + session: URLSession, + domain: String, + sinceID: Mastodon.Entity.Status.ID? = nil, + limit: Int?, + authorization: Mastodon.API.OAuth.Authorization + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: mutesEndpointURL(domain: domain), + query: MutesQuery(sinceID: sinceID, limit: limit), + authorization: authorization + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: [Mastodon.Entity.Account].self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + + struct MutesQuery: GetQuery { + private let sinceID: Mastodon.Entity.Status.ID? + private let limit: Int? + + public init( + sinceID: Mastodon.Entity.Status.ID?, + limit: Int? + ) { + self.sinceID = sinceID + self.limit = limit + } + + var queryItems: [URLQueryItem]? { + var items: [URLQueryItem] = [] + sinceID.flatMap { items.append(URLQueryItem(name: "since_id", value: $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/API/Mastodon+API+Statuses+Translate.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Statuses+Translate.swift new file mode 100644 index 000000000..c3e790b67 --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Statuses+Translate.swift @@ -0,0 +1,48 @@ +// +// Mastodon+API+Statuses+Translate.swift +// +// +// Created by Marcus Kida on 02.12.2022. +// + +import Foundation +import Combine + +extension Mastodon.API.Statuses { + + private static func translateEndpointURL(domain: String, statusID: Mastodon.Entity.Status.ID) -> URL { + return Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("statuses") + .appendingPathComponent(statusID) + .appendingPathComponent("translate") + } + + /// Translate Status + /// + /// Translate a given Status. + /// + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - statusID: id for status + /// - authorization: User token. Could be nil if status is public + /// - Returns: `AnyPublisher` contains `Status` nested in the response + public static func translate( + session: URLSession, + domain: String, + statusID: Mastodon.Entity.Status.ID, + authorization: Mastodon.API.OAuth.Authorization? + ) -> AnyPublisher, Error> { + let request = Mastodon.API.post( + url: translateEndpointURL(domain: domain, statusID: statusID), + query: nil, + authorization: authorization + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: Mastodon.Entity.Translation.self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } +} diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Tags.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Tags.swift new file mode 100644 index 000000000..42f8b4fd3 --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Tags.swift @@ -0,0 +1,117 @@ +// +// Mastodin+API+Tags.swift +// +// +// Created by Marcus Kida on 23.11.22. +// + +import Combine +import Foundation + +extension Mastodon.API.Tags { + static func tagsEndpointURL(domain: String) -> URL { + return Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("tags") + } + + /// Tags + /// + /// View information about a single tag. + /// + /// - Since: 4.0.0 + /// - Version: 4.0.3 + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/tags/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - authorization: User token + /// - tagId: The Hashtag + /// - Returns: `AnyPublisher` contains `Tag` nested in the response + public static func getTagInformation( + session: URLSession, + domain: String, + tagId: String, + authorization: Mastodon.API.OAuth.Authorization + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: tagsEndpointURL(domain: domain).appendingPathComponent(tagId), + query: nil, + authorization: authorization + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: Mastodon.Entity.Tag.self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + + /// Tags + /// + /// Follow a hashtag. + /// + /// - Since: 4.0.0 + /// - Version: 4.0.3 + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/tags/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - authorization: User token + /// - tagId: The Hashtag + /// - Returns: `AnyPublisher` contains `Tag` nested in the response + public static func followTag( + session: URLSession, + domain: String, + tagId: String, + authorization: Mastodon.API.OAuth.Authorization + ) -> AnyPublisher, Error> { + let request = Mastodon.API.post( + url: tagsEndpointURL(domain: domain).appendingPathComponent(tagId) + .appendingPathComponent("follow"), + query: nil, + authorization: authorization + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: Mastodon.Entity.Tag.self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + + /// Tags + /// + /// Unfollow a hashtag. + /// + /// - Since: 4.0.0 + /// - Version: 4.0.3 + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/tags/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - authorization: User token + /// - tagId: The Hashtag + /// - Returns: `AnyPublisher` contains `Tag` nested in the response + public static func unfollowTag( + session: URLSession, + domain: String, + tagId: String, + authorization: Mastodon.API.OAuth.Authorization + ) -> AnyPublisher, Error> { + let request = Mastodon.API.post( + url: tagsEndpointURL(domain: domain).appendingPathComponent(tagId) + .appendingPathComponent("unfollow"), + query: nil, + authorization: authorization + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: Mastodon.Entity.Tag.self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } +} diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+V2+Instance.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+V2+Instance.swift new file mode 100644 index 000000000..e276fddba --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+V2+Instance.swift @@ -0,0 +1,50 @@ +import Foundation +import Combine + +extension Mastodon.API.V2.Instance { + + private static func instanceEndpointURL(domain: String) -> URL { + return Mastodon.API.endpointV2URL(domain: domain).appendingPathComponent("instance") + } + + /// Information about the server + /// + /// - Since: 4.0.0 + /// - Version: 4.0.0 + /// # Last Update + /// 2022/12/09 + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/instance/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - Returns: `AnyPublisher` contains `Instance` nested in the response + public static func instance( + session: URLSession, + domain: String + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: instanceEndpointURL(domain: domain), + query: nil, + authorization: nil + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value: Mastodon.Entity.V2.Instance + + do { + value = try Mastodon.API.decode(type: Mastodon.Entity.V2.Instance.self, from: data, response: response) + } catch { + if let response = response as? HTTPURLResponse, 400 ..< 500 ~= response.statusCode { + // For example, AUTHORIZED_FETCH may result in authentication errors + value = Mastodon.Entity.V2.Instance(domain: domain) + } else { + throw error + } + } + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + +} diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API.swift index 5d507bace..f85d50bd0 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API.swift @@ -112,6 +112,7 @@ extension Mastodon.API { public enum Polls { } public enum Reblog { } public enum Statuses { } + public enum Tags {} public enum Timeline { } public enum Trends { } public enum Suggestions { } @@ -125,6 +126,7 @@ extension Mastodon.API.V2 { public enum Search { } public enum Suggestions { } public enum Media { } + public enum Instance { } } extension Mastodon.API { diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+InstanceV2.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+InstanceV2.swift new file mode 100644 index 000000000..d662c24c2 --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+InstanceV2.swift @@ -0,0 +1,108 @@ +import Foundation + +extension Mastodon.Entity.V2 { + /// Instance + /// + /// - Since: 4.0.0 + /// - Version: 4.0.3 + /// # Last Update + /// 2022/12/09 + /// # Reference + /// [Document](https://docs.joinmastodon.org/entities/instance/) + public struct Instance: Codable { + + public let domain: String? + public let title: String + public let description: String + public let shortDescription: String? + public let email: String? + public let version: String? + public let languages: [String]? // (ISO 639 Part 1-5 language codes) + public let registrations: Mastodon.Entity.V2.Instance.Registrations? + public let approvalRequired: Bool? + public let invitesEnabled: Bool? + public let urls: Mastodon.Entity.Instance.InstanceURL? + public let statistics: Mastodon.Entity.Instance.Statistics? + + public let thumbnail: Thumbnail? + public let contactAccount: Mastodon.Entity.Account? + public let rules: [Mastodon.Entity.Instance.Rule]? + + // https://github.com/mastodon/mastodon/pull/16485 + public let configuration: Configuration? + + public init(domain: String, approvalRequired: Bool? = nil) { + self.domain = domain + self.title = domain + self.description = "" + self.shortDescription = nil + self.email = "" + self.version = nil + self.languages = nil + self.registrations = nil + self.approvalRequired = approvalRequired + self.invitesEnabled = nil + self.urls = nil + self.statistics = nil + self.thumbnail = nil + self.contactAccount = nil + self.rules = nil + self.configuration = nil + } + + enum CodingKeys: String, CodingKey { + case domain + case title + case description + case shortDescription = "short_description" + case email + case version + case languages + case registrations + case approvalRequired = "approval_required" + case invitesEnabled = "invites_enabled" + case urls + case statistics = "stats" + + case thumbnail + case contactAccount = "contact_account" + case rules + + case configuration + } + } +} + +extension Mastodon.Entity.V2.Instance { + public struct Configuration: Codable { + public let statuses: Mastodon.Entity.Instance.Configuration.Statuses? + public let mediaAttachments: Mastodon.Entity.Instance.Configuration.MediaAttachments? + public let polls: Mastodon.Entity.Instance.Configuration.Polls? + public let translation: Mastodon.Entity.V2.Instance.Configuration.Translation? + + enum CodingKeys: String, CodingKey { + case statuses + case mediaAttachments = "media_attachments" + case polls + case translation + } + } +} + +extension Mastodon.Entity.V2.Instance { + public struct Registrations: Codable { + public let enabled: Bool + } +} + +extension Mastodon.Entity.V2.Instance.Configuration { + public struct Translation: Codable { + public let enabled: Bool + } +} + +extension Mastodon.Entity.V2.Instance { + public struct Thumbnail: Codable { + public let url: String? + } +} diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift index 84875359a..d40bf8915 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift @@ -11,9 +11,9 @@ extension Mastodon.Entity { /// Tag /// /// - Since: 0.9.0 - /// - Version: 3.3.0 + /// - Version: 4.0.0 /// # Last Update - /// 2021/1/28 + /// 2022/11/22 /// # Reference /// [Document](https://docs.joinmastodon.org/entities/tag/) public struct Tag: Hashable, Codable { @@ -23,11 +23,13 @@ extension Mastodon.Entity { public let url: String public let history: [History]? + public let following: Bool? enum CodingKeys: String, CodingKey { case name case url case history + case following } public static func == (lhs: Mastodon.Entity.Tag, rhs: Mastodon.Entity.Tag) -> Bool { @@ -39,5 +41,9 @@ extension Mastodon.Entity { hasher.combine(name) hasher.combine(url) } + + public func copy(following: Bool?) -> Self { + Tag(name: name, url: url, history: history, following: following) + } } } diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Translation.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Translation.swift new file mode 100644 index 000000000..f500453f1 --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Translation.swift @@ -0,0 +1,22 @@ +// +// Mastodon+Entity+Translation.swift +// +// +// Created by Marcus Kida on 02.12.22. +// + +import Foundation + +extension Mastodon.Entity { + public struct Translation: Codable { + public let content: String? + public let sourceLanguage: String? + public let provider: String? + + enum CodingKeys: String, CodingKey { + case content + case sourceLanguage = "detected_source_language" + case provider + } + } +} diff --git a/MastodonSDK/Sources/MastodonSDK/Response/Mastodon+Response+Content.swift b/MastodonSDK/Sources/MastodonSDK/Response/Mastodon+Response+Content.swift index 6cf95752b..aa156ac16 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 linkIDs: [String: Mastodon.Entity.Status.ID] public let offset: Int? init(link: String) { @@ -135,6 +136,33 @@ extension Mastodon.Response { let offset = link[range] return Int(offset) }() + self.linkIDs = { + var linkIDs = [String: Mastodon.Entity.Status.ID]() + let links = link.components(separatedBy: ", ") + for link in links { + guard let regex = try? NSRegularExpression(pattern: "<(.*)>; *rel=\"(.*)\"") else { return [:] } + let results = regex.matches(in: link, options: [], range: NSRange(link.startIndex.. " - // for mention: "@ " + // allow dismissing the compose view without confirmation if content == intialContent @Published public var initialContent = "" @Published public var content = "" @Published public var contentWeightedLength = 0 @@ -138,11 +137,12 @@ public final class ComposeContentViewModel: NSObject, ObservableObject { public init( context: AppContext, authContext: AuthContext, - kind: Kind + destination: Destination, + initialContent: String ) { self.context = context self.authContext = authContext - self.kind = kind + self.destination = destination self.visibility = { // default private when user locked var visibility: Mastodon.Entity.Status.Visibility = { @@ -152,8 +152,7 @@ public final class ComposeContentViewModel: NSObject, ObservableObject { return author.locked ? .private : .public }() // set visibility for reply post - switch kind { - case .reply(let record): + if case .reply(let record) = destination { context.managedObjectContext.performAndWait { guard let status = record.object(in: context.managedObjectContext) else { assertionFailure() @@ -173,8 +172,6 @@ public final class ComposeContentViewModel: NSObject, ObservableObject { break } } - default: - break } return visibility }() @@ -185,7 +182,8 @@ public final class ComposeContentViewModel: NSObject, ObservableObject { // end init // setup initial value - switch kind { + let initialContentWithSpace = initialContent.isEmpty ? "" : initialContent + " " + switch destination { case .reply(let record): context.managedObjectContext.performAndWait { guard let status = record.object(in: context.managedObjectContext) else { @@ -214,29 +212,15 @@ public final class ComposeContentViewModel: NSObject, ObservableObject { } let initialComposeContent = mentionAccts.joined(separator: " ") - let preInsertedContent: String? = initialComposeContent.isEmpty ? nil : initialComposeContent + " " - self.initialContent = preInsertedContent ?? "" - self.content = preInsertedContent ?? "" + let preInsertedContent = initialComposeContent.isEmpty ? "" : initialComposeContent + " " + self.initialContent = preInsertedContent + initialContentWithSpace + self.content = preInsertedContent + initialContentWithSpace } - case .hashtag(let hashtag): - let initialComposeContent = "#" + hashtag - UITextChecker.learnWord(initialComposeContent) - let preInsertedContent = initialComposeContent + " " - self.initialContent = preInsertedContent - self.content = preInsertedContent - case .mention(let record): - context.managedObjectContext.performAndWait { - guard let user = record.object(in: context.managedObjectContext) else { return } - let initialComposeContent = "@" + user.acct - UITextChecker.learnWord(initialComposeContent) - let preInsertedContent = initialComposeContent + " " - self.initialContent = preInsertedContent - self.content = preInsertedContent - } - case .post: - break + case .topLevel: + self.initialContent = initialContentWithSpace + self.content = initialContentWithSpace } - + // set limit let _configuration: Mastodon.Entity.Instance.Configuration? = { var configuration: Mastodon.Entity.Instance.Configuration? = nil @@ -443,11 +427,9 @@ extension ComposeContentViewModel { } extension ComposeContentViewModel { - public enum Kind { - case post - case hashtag(hashtag: String) - case mention(user: ManagedObjectRecord) - case reply(status: ManagedObjectRecord) + public enum Destination { + case topLevel + case reply(parent: ManagedObjectRecord) } public enum ScrollViewState { @@ -530,10 +512,10 @@ extension ComposeContentViewModel { return MastodonStatusPublisher( author: author, replyTo: { - switch self.kind { - case .reply(let status): return status - default: return nil + if case .reply(let status) = destination { + return status } + return nil }(), isContentWarningComposing: isContentWarningActive, contentWarning: contentWarning, diff --git a/MastodonSDK/Sources/MastodonUI/SwiftUI/MetaTextViewRepresentable.swift b/MastodonSDK/Sources/MastodonUI/SwiftUI/MetaTextViewRepresentable.swift index 8796feb06..9e4d968de 100644 --- a/MastodonSDK/Sources/MastodonUI/SwiftUI/MetaTextViewRepresentable.swift +++ b/MastodonSDK/Sources/MastodonUI/SwiftUI/MetaTextViewRepresentable.swift @@ -50,6 +50,8 @@ public struct MetaTextViewRepresentable: UIViewRepresentable { .foregroundColor: Asset.Colors.brand.color, ] + metaText.paragraphStyle = NSMutableParagraphStyle() + configurationHandler(metaText) metaText.configure(content: PlaintextMetaContent(string: string)) diff --git a/MastodonSDK/Sources/MastodonUI/Vendor/MetaTextView+PasteExtensions.swift b/MastodonSDK/Sources/MastodonUI/Vendor/MetaTextView+PasteExtensions.swift index 8fe1949af..f3fa8e0e4 100644 --- a/MastodonSDK/Sources/MastodonUI/Vendor/MetaTextView+PasteExtensions.swift +++ b/MastodonSDK/Sources/MastodonUI/Vendor/MetaTextView+PasteExtensions.swift @@ -13,6 +13,8 @@ extension MetaTextView { public override func paste(_ sender: Any?) { super.paste(sender) + // fix #660 + // https://github.com/mastodon/mastodon-ios/issues/660 var nextResponder = self.next; // Force the event to bubble through ALL responders diff --git a/MastodonSDK/Sources/MastodonUI/View/Button/HUDButton.swift b/MastodonSDK/Sources/MastodonUI/View/Button/HUDButton.swift new file mode 100644 index 000000000..26dda32d6 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Button/HUDButton.swift @@ -0,0 +1,76 @@ +// +// HUDButton.swift +// Mastodon +// +// Created by Jed Fox on 2022-11-24. +// + +import UIKit + +public class HUDButton: UIView { + + public static let height: CGFloat = 30 + + let background: UIVisualEffectView = { + let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial)) + backgroundView.layer.masksToBounds = true + backgroundView.layer.cornerRadius = HUDButton.height * 0.5 + return backgroundView + }() + + let vibrancyView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: UIBlurEffect(style: .systemMaterial))) + + public let button: UIButton = { + let button = HighlightDimmableButton() + button.expandEdgeInsets = .constant(-10) + button.contentEdgeInsets = .constant(7) + button.imageView?.tintColor = .label + button.titleLabel?.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .bold)) + return button + }() + + public init(configure: (UIButton) -> Void) { + super.init(frame: .zero) + + configure(button) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + + func _init() { + translatesAutoresizingMaskIntoConstraints = false + background.translatesAutoresizingMaskIntoConstraints = false + addSubview(background) + background.pinToParent() + vibrancyView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + background.contentView.addSubview(vibrancyView) + + button.translatesAutoresizingMaskIntoConstraints = false + vibrancyView.contentView.addSubview(button) + button.pinToParent() + NSLayoutConstraint.activate([ + heightAnchor.constraint(equalToConstant: HUDButton.height).priority(.defaultHigh), + ]) + } + + public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + button.titleLabel?.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .bold)) + } + + public override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { + button.point(inside: button.convert(point, from: self), with: event) + } + + public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if self.point(inside: point, with: event) { + return button + } else { + return nil + } + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Container/TouchTransparentStackView.swift b/MastodonSDK/Sources/MastodonUI/View/Container/TouchTransparentStackView.swift new file mode 100644 index 000000000..e519c0cf7 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Container/TouchTransparentStackView.swift @@ -0,0 +1,26 @@ +// +// TouchTransparentStackView.swift +// +// +// Created by Jed Fox on 2022-12-21. +// + +import UIKit + +/// A subclass of `UIStackView` that allows touches that aren’t captured by any +/// of its subviews to pass through to views beneath this view in the Z-order. +public class TouchTransparentStackView: UIStackView { + // allow subview hit boxes to grow outside of this view’s bounds + public override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { + subviews.contains { $0.point(inside: $0.convert(point, from: self), with: event) } + } + + // allow taps on blank areas to pass through + public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + let view = super.hitTest(point, with: event) + if view == self { + return nil + } + return view + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/MediaAltTextOverlay.swift b/MastodonSDK/Sources/MastodonUI/View/Content/MediaAltTextOverlay.swift new file mode 100644 index 000000000..a625be292 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/MediaAltTextOverlay.swift @@ -0,0 +1,78 @@ +// +// MediaAltTextOverlay.swift +// +// +// Created by Jed Fox on 2022-12-20. +// + +import SwiftUI + +struct MediaAltTextOverlay: View { + var altDescription: String? + + @State private var showingAlt = false + @Namespace private var namespace + + var body: some View { + GeometryReader { geom in + ZStack { + if let altDescription { + if showingAlt { + HStack(alignment: .top) { + Text(altDescription) + Spacer() + Button(action: { showingAlt = false }) { + Image(systemName: "xmark.circle.fill") + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: 20, height: 20) + } + } + .padding(8) + .matchedGeometryEffect(id: "background", in: namespace, properties: .position) + .transition( + .scale(scale: 0.2, anchor: .bottomLeading) + .combined(with: .opacity) + ) + } else { + Button("ALT") { showingAlt = true } + .font(.caption.weight(.semibold)) + .padding(.horizontal, 8) + .padding(.vertical, 3) + .matchedGeometryEffect(id: "background", in: namespace, properties: .position) + .transition( + .scale(scale: 3, anchor: .trailing) + .combined(with: .opacity) + ) + } + } + } + .foregroundColor(.white) + .tint(.white) + .background(Color.black.opacity(0.85)) + .cornerRadius(4) + .overlay( + .white.opacity(0.5), + in: RoundedRectangle(cornerRadius: 4) + .inset(by: -0.5) + .stroke(lineWidth: 0.5) + ) + .animation(.spring(response: 0.3), value: showingAlt) + .frame(width: geom.size.width, height: geom.size.height, alignment: .bottomLeading) + } + .padding(.horizontal, 16) + .padding(.vertical, 8) + .onChange(of: altDescription) { _ in + showingAlt = false + } + } +} + +struct MediaAltTextOverlay_Previews: PreviewProvider { + static var previews: some View { + MediaAltTextOverlay(altDescription: "Hello, world!") + .frame(height: 300) + .background(Color.gray) + .previewLayout(.sizeThatFits) + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift index 438baff7e..05c8eee14 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift @@ -21,6 +21,8 @@ extension MediaView { public let info: Info public let blurhash: String? + public let index: Int + public let total: Int @Published public var isReveal = true @Published public var previewImage: UIImage? @@ -29,10 +31,14 @@ extension MediaView { public init( info: MediaView.Configuration.Info, - blurhash: String? + blurhash: String?, + index: Int, + total: Int ) { self.info = info self.blurhash = blurhash + self.index = index + self.total = total } public var aspectRadio: CGSize { @@ -101,19 +107,16 @@ extension MediaView.Configuration { public struct ImageInfo: Hashable { public let aspectRadio: CGSize public let assetURL: String? + public let altDescription: String? public init( aspectRadio: CGSize, - assetURL: String? + assetURL: String?, + altDescription: String? ) { self.aspectRadio = aspectRadio self.assetURL = assetURL - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(aspectRadio.width) - hasher.combine(aspectRadio.height) - assetURL.flatMap { hasher.combine($0) } + self.altDescription = altDescription } } @@ -121,26 +124,21 @@ extension MediaView.Configuration { public let aspectRadio: CGSize public let assetURL: String? public let previewURL: String? + public let altDescription: String? public let durationMS: Int? public init( aspectRadio: CGSize, assetURL: String?, previewURL: String?, + altDescription: String?, durationMS: Int? ) { self.aspectRadio = aspectRadio self.assetURL = assetURL self.previewURL = previewURL self.durationMS = durationMS - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(aspectRadio.width) - hasher.combine(aspectRadio.height) - assetURL.flatMap { hasher.combine($0) } - previewURL.flatMap { hasher.combine($0) } - durationMS.flatMap { hasher.combine($0) } + self.altDescription = altDescription } } @@ -187,41 +185,51 @@ extension MediaView { aspectRadio: attachment.size, assetURL: attachment.assetURL, previewURL: attachment.previewURL, + altDescription: attachment.altDescription, durationMS: attachment.durationMS ) } let status = status.reblog ?? status let attachments = status.attachments - let configurations = attachments.map { attachment -> MediaView.Configuration in + let configurations = attachments.enumerated().map { (idx, attachment) -> MediaView.Configuration in let configuration: MediaView.Configuration = { switch attachment.kind { case .image: let info = MediaView.Configuration.ImageInfo( aspectRadio: attachment.size, - assetURL: attachment.assetURL + assetURL: attachment.assetURL, + altDescription: attachment.altDescription ) return .init( info: .image(info: info), - blurhash: attachment.blurhash + blurhash: attachment.blurhash, + index: idx, + total: attachments.count ) case .video: let info = videoInfo(from: attachment) return .init( info: .video(info: info), - blurhash: attachment.blurhash + blurhash: attachment.blurhash, + index: idx, + total: attachments.count ) case .gifv: let info = videoInfo(from: attachment) return .init( info: .gif(info: info), - blurhash: attachment.blurhash + blurhash: attachment.blurhash, + index: idx, + total: attachments.count ) case .audio: let info = videoInfo(from: attachment) return .init( info: .video(info: info), - blurhash: attachment.blurhash + blurhash: attachment.blurhash, + index: idx, + total: attachments.count ) } // end switch }() diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/MediaView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/MediaView.swift index 54560a8ce..d543e64c8 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/MediaView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/MediaView.swift @@ -10,18 +10,15 @@ import AVKit import UIKit import Combine import AlamofireImage +import SwiftUI +import MastodonLocalization +import MastodonAsset public final class MediaView: UIView { var _disposeBag = Set() public static let cornerRadius: CGFloat = 0 - public static let durationFormatter: DateComponentsFormatter = { - let formatter = DateComponentsFormatter() - formatter.zeroFormattingBehavior = .pad - formatter.allowedUnits = [.minute, .second] - return formatter - }() public static let placeholderImage = UIImage.placeholder(color: .systemGray6) public let container = TouchBlockingView() @@ -53,11 +50,20 @@ public final class MediaView: UIView { return playerViewController }() private var playerLooper: AVPlayerLooper? - private(set) lazy var playbackImageView: UIImageView = { + + private(set) lazy var playbackImageView: UIView = { + let wrapper = UIView() + let imageView = UIImageView() + imageView.translatesAutoresizingMaskIntoConstraints = false imageView.image = UIImage(systemName: "play.circle.fill") - imageView.tintColor = .white - return imageView + imageView.tintColor = Asset.Colors.Label.primary.color + wrapper.addSubview(imageView) + imageView.pinToParent(padding: .init(top: 8, left: 8, bottom: 8, right: 8)) + wrapper.backgroundColor = Asset.Theme.Mastodon.systemBackground.color.withAlphaComponent(0.8) + wrapper.applyCornerRadius(radius: 8) + + return wrapper }() private(set) lazy var indicatorBlurEffectView: UIVisualEffectView = { @@ -77,6 +83,12 @@ public final class MediaView: UIView { return label }() + let altViewController: UIHostingController = { + let vc = UIHostingController(rootView: MediaAltTextOverlay()) + vc.view.backgroundColor = .clear + return vc + }() + public override init(frame: CGRect) { super.init(frame: frame) _init() @@ -118,18 +130,18 @@ extension MediaView { case .image(let info): layoutImage() bindImage(configuration: configuration, info: info) - accessibilityLabel = "Show image" // TODO: i18n + accessibilityHint = L10n.Common.Controls.Status.Media.expandImageHint case .gif(let info): layoutGIF() bindGIF(configuration: configuration, info: info) - accessibilityLabel = "Show GIF" // TODO: i18n + accessibilityHint = L10n.Common.Controls.Status.Media.expandGifHint case .video(let info): layoutVideo() bindVideo(configuration: configuration, info: info) - accessibilityLabel = "Show video player" // TODO: i18n + accessibilityHint = L10n.Common.Controls.Status.Media.expandVideoHint } - accessibilityHint = "Tap then hold to show menu" // TODO: i18n + accessibilityTraits.insert([.button, .image]) layoutBlurhash() bindBlurhash(configuration: configuration) @@ -139,6 +151,7 @@ extension MediaView { imageView.translatesAutoresizingMaskIntoConstraints = false container.addSubview(imageView) imageView.pinToParent() + layoutAlt() } private func bindImage(configuration: Configuration, info: Configuration.ImageInfo) { @@ -157,8 +170,10 @@ extension MediaView { self.imageView.image = image } .store(in: &configuration.disposeBag) + + bindAlt(configuration: configuration, altDescription: info.altDescription) } - + private func layoutGIF() { // use view controller as View here playerViewController.view.translatesAutoresizingMaskIntoConstraints = false @@ -167,6 +182,8 @@ extension MediaView { setupIndicatorViewHierarchy() playerIndicatorLabel.attributedText = NSAttributedString(string: "GIF") + + layoutAlt() } private func bindGIF(configuration: Configuration, info: Configuration.VideoInfo) { @@ -177,6 +194,8 @@ extension MediaView { // auto play for GIF player.play() + + bindAlt(configuration: configuration, altDescription: info.altDescription) } private func layoutVideo() { @@ -195,11 +214,26 @@ extension MediaView { private func bindVideo(configuration: Configuration, info: Configuration.VideoInfo) { let imageInfo = Configuration.ImageInfo( aspectRadio: info.aspectRadio, - assetURL: info.previewURL + assetURL: info.previewURL, + altDescription: info.altDescription ) bindImage(configuration: configuration, info: imageInfo) } + private func bindAlt(configuration: Configuration, altDescription: String?) { + if configuration.total > 1 { + accessibilityLabel = L10n.Common.Controls.Status.Media.accessibilityLabel( + altDescription ?? "", + configuration.index + 1, + configuration.total + ) + } else { + accessibilityLabel = altDescription + } + + altViewController.rootView.altDescription = altDescription + } + private func layoutBlurhash() { blurhashImageView.translatesAutoresizingMaskIntoConstraints = false container.addSubview(blurhashImageView) @@ -228,6 +262,12 @@ extension MediaView { .store(in: &_disposeBag) } + private func layoutAlt() { + altViewController.view.translatesAutoresizingMaskIntoConstraints = false + container.addSubview(altViewController.view) + altViewController.view.pinToParent() + } + public func prepareForReuse() { _disposeBag.removeAll() @@ -263,6 +303,8 @@ extension MediaView { container.removeFromSuperview() container.removeConstraints(container.constraints) + altViewController.rootView.altDescription = nil + // reset configuration configuration = nil } diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift index 7f44232aa..8403be756 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift @@ -39,9 +39,12 @@ extension NewsView { let configuration = MediaView.Configuration( info: .image(info: .init( aspectRadio: CGSize(width: link.width, height: link.height), - assetURL: link.image + assetURL: link.image, + altDescription: nil )), - blurhash: link.blurhash + blurhash: link.blurhash, + index: 1, + total: 1 ) imageView.setup(configuration: configuration) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView+ViewModel.swift index 714cf676d..ed038f47f 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView+ViewModel.swift @@ -23,7 +23,8 @@ extension NotificationView { public var objects = Set() let logger = Logger(subsystem: "NotificationView", category: "ViewModel") - + + @Published public var context: AppContext? @Published public var authContext: AuthContext? @Published public var type: MastodonNotificationType? @@ -37,6 +38,7 @@ extension NotificationView { @Published public var isMyself = false @Published public var isMuting = false @Published public var isBlocking = false + @Published public var isTranslated = false @Published public var timestamp: Date? @@ -56,6 +58,9 @@ extension NotificationView.ViewModel { bindAuthorMenu(notificationView: notificationView) bindFollowRequest(notificationView: notificationView) + $context + .assign(to: \.context, on: notificationView.statusView.viewModel) + .store(in: &disposeBag) $authContext .assign(to: \.authContext, on: notificationView.statusView.viewModel) .store(in: &disposeBag) @@ -203,20 +208,44 @@ extension NotificationView.ViewModel { $authorName, $isMuting, $isBlocking, - $isMyself + Publishers.CombineLatest( + $isMyself, + $isTranslated + ) ) - .sink { authorName, isMuting, isBlocking, isMyself in + .sink { [weak self] authorName, isMuting, isBlocking, isMyselfIsTranslated in guard let name = authorName?.string else { notificationView.menuButton.menu = nil return } + let (isMyself, isTranslated) = isMyselfIsTranslated + + lazy var instanceConfigurationV2: Mastodon.Entity.V2.Instance.Configuration? = { + guard + let self = self, + let context = self.context, + let authContext = self.authContext + else { return nil } + + var configuration: Mastodon.Entity.V2.Instance.Configuration? = nil + context.managedObjectContext.performAndWait { + guard let authentication = authContext.mastodonAuthenticationBox.authenticationRecord.object(in: context.managedObjectContext) + else { return } + configuration = authentication.instance?.configurationV2 + } + return configuration + }() + let menuContext = NotificationView.AuthorMenuContext( name: name, isMuting: isMuting, isBlocking: isBlocking, isMyself: isMyself, - isBookmarking: false // no bookmark action display for notification item + isBookmarking: false, // no bookmark action display for notification item + isTranslationEnabled: instanceConfigurationV2?.translation?.enabled == true, + isTranslated: isTranslated, + statusLanguage: "" ) let (menu, actions) = notificationView.setupAuthorMenu(menuContext: menuContext) notificationView.menuButton.menu = menu diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift index ddc1add5c..9196c340e 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift @@ -496,7 +496,10 @@ extension NotificationView { // MARK: - StatusViewDelegate extension NotificationView: StatusViewDelegate { - + public func statusView(_ statusView: StatusView, didTapCardWithURL url: URL) { + assertionFailure() + } + public func statusView(_ statusView: StatusView, headerDidPressed header: UIView) { // do nothing } @@ -599,6 +602,15 @@ extension NotificationView: StatusViewDelegate { assertionFailure() } + public func statusView(_ statusView: StatusView, cardControl: StatusCardControl, didTapURL url: URL) { + assertionFailure() + } + + public func statusView(_ statusView: StatusView, cardControlMenu: StatusCardControl) -> UIMenu? { + assertionFailure() + return nil + } + } // MARK: - MastodonMenuDelegate diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/PollOptionView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/PollOptionView+ViewModel.swift index a91f57dc2..e3e34d1cb 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/PollOptionView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/PollOptionView+ViewModel.swift @@ -175,7 +175,7 @@ extension PollOptionView.ViewModel { view.voteProgressStripView.setProgress(0.0, animated: false) case .reveal(let voted, let percentage, let animating): view.optionPercentageLabel.isHidden = false - view.optionPercentageLabel.text = String(Int(100 * percentage)) + "%" + view.optionPercentageLabel.text = String(Int(round(100 * percentage))) + "%" view.voteProgressStripView.isHidden = false view.voteProgressStripView.tintColor = voted ? self.primaryStripProgressViewTintColor : self.secondaryStripProgressViewTintColor view.voteProgressStripView.setProgress(CGFloat(percentage), animated: animating) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift index 55d270f74..beb7680a8 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift @@ -43,7 +43,7 @@ extension ProfileCardView { @Published public var isMuting = false @Published public var isBlocking = false @Published public var isBlockedBy = false - + @Published public var groupedAccessibilityLabel = "" @Published public var familiarFollowers: Mastodon.Entity.FamiliarFollowers? @@ -173,6 +173,19 @@ extension ProfileCardView.ViewModel { } private func bindDashboard(view: ProfileCardView) { + relationshipViewModel.$isMyself + .sink { isMyself in + if isMyself { + view.statusDashboardView.postDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.myPosts + view.statusDashboardView.followingDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.myFollowing + view.statusDashboardView.followersDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.myFollowers + } else { + view.statusDashboardView.postDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.otherPosts + view.statusDashboardView.followingDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.otherFollowing + view.statusDashboardView.followersDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.otherFollowers + } + } + .store(in: &disposeBag) $statusesCount .receive(on: DispatchQueue.main) .sink { count in diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift index 0631875c0..ef40ab7fc 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift @@ -149,12 +149,22 @@ extension StatusAuthorView { public let isBlocking: Bool public let isMyself: Bool public let isBookmarking: Bool + + public let isTranslationEnabled: Bool + public let isTranslated: Bool + public let statusLanguage: String? } public func setupAuthorMenu(menuContext: AuthorMenuContext) -> (UIMenu, [UIAccessibilityCustomAction]) { var actions = [MastodonMenu.Action]() if !menuContext.isMyself { + if let statusLanguage = menuContext.statusLanguage, menuContext.isTranslationEnabled, !menuContext.isTranslated { + actions.append( + .translateStatus(.init(language: statusLanguage)) + ) + } + actions.append(contentsOf: [ .muteUser(.init( name: menuContext.name, diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusCardControl.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusCardControl.swift new file mode 100644 index 000000000..530ceea20 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusCardControl.swift @@ -0,0 +1,329 @@ +// +// OpenGraphView.swift +// +// +// Created by Kyle Bashour on 11/11/22. +// + +import AlamofireImage +import Combine +import MastodonAsset +import MastodonCore +import MastodonLocalization +import CoreDataStack +import UIKit +import WebKit + +public protocol StatusCardControlDelegate: AnyObject { + func statusCardControl(_ statusCardControl: StatusCardControl, didTapURL url: URL) + func statusCardControlMenu(_ statusCardControl: StatusCardControl) -> UIMenu? +} + +public final class StatusCardControl: UIControl { + public weak var delegate: StatusCardControlDelegate? + + private var disposeBag = Set() + + private let containerStackView = UIStackView() + private let labelStackView = UIStackView() + + private let highlightView = UIView() + private let dividerView = UIView() + private let imageView = UIImageView() + private let titleLabel = UILabel() + private let linkLabel = UILabel() + private lazy var showEmbedButton: UIButton = { + var configuration = UIButton.Configuration.gray() + configuration.background.visualEffect = UIBlurEffect(style: .systemUltraThinMaterial) + configuration.baseBackgroundColor = .clear + configuration.cornerStyle = .capsule + configuration.buttonSize = .large + configuration.title = L10n.Common.Controls.Status.loadEmbed + configuration.image = UIImage(systemName: "play.fill") + configuration.imagePadding = 12 + return UIButton(configuration: configuration, primaryAction: UIAction { [weak self] _ in + self?.showWebView() + }) + }() + private var html = "" + + private static let cardContentPool = WKProcessPool() + private var webView: WKWebView? + + private var layout: Layout? + private var layoutConstraints: [NSLayoutConstraint] = [] + private var dividerConstraint: NSLayoutConstraint? + + public override var isHighlighted: Bool { + didSet { + // override UIKit behavior of highlighting subviews when cell is highlighted + if isHighlighted, + let cell = sequence(first: self, next: \.superview).first(where: { $0 is UITableViewCell }) as? UITableViewCell { + highlightView.isHidden = cell.isHighlighted + } else { + highlightView.isHidden = !isHighlighted + } + } + } + + public override init(frame: CGRect) { + super.init(frame: frame) + + apply(theme: ThemeService.shared.currentTheme.value) + + ThemeService.shared.currentTheme.sink { [weak self] theme in + self?.apply(theme: theme) + }.store(in: &disposeBag) + + clipsToBounds = true + layer.cornerCurve = .continuous + layer.cornerRadius = 10 + + maximumContentSizeCategory = .accessibilityLarge + highlightView.backgroundColor = UIColor.label.withAlphaComponent(0.1) + highlightView.isHidden = true + + titleLabel.numberOfLines = 2 + titleLabel.textColor = Asset.Colors.Label.primary.color + titleLabel.font = .preferredFont(forTextStyle: .body) + + linkLabel.numberOfLines = 1 + linkLabel.textColor = Asset.Colors.Label.secondary.color + linkLabel.font = .preferredFont(forTextStyle: .subheadline) + + imageView.tintColor = Asset.Colors.Label.secondary.color + imageView.contentMode = .scaleAspectFill + imageView.clipsToBounds = true + imageView.setContentHuggingPriority(.zero, for: .horizontal) + imageView.setContentHuggingPriority(.zero, for: .vertical) + imageView.setContentCompressionResistancePriority(.zero, for: .horizontal) + imageView.setContentCompressionResistancePriority(.zero, for: .vertical) + + labelStackView.addArrangedSubview(titleLabel) + labelStackView.addArrangedSubview(linkLabel) + labelStackView.layoutMargins = .init(top: 10, left: 10, bottom: 10, right: 10) + labelStackView.isLayoutMarginsRelativeArrangement = true + labelStackView.axis = .vertical + labelStackView.spacing = 2 + + containerStackView.addArrangedSubview(imageView) + containerStackView.addArrangedSubview(dividerView) + containerStackView.addArrangedSubview(labelStackView) + containerStackView.isUserInteractionEnabled = false + containerStackView.distribution = .fill + + addSubview(containerStackView) + addSubview(highlightView) + addSubview(showEmbedButton) + + containerStackView.translatesAutoresizingMaskIntoConstraints = false + highlightView.translatesAutoresizingMaskIntoConstraints = false + showEmbedButton.translatesAutoresizingMaskIntoConstraints = false + dividerView.translatesAutoresizingMaskIntoConstraints = false + + containerStackView.pinToParent() + highlightView.pinToParent() + NSLayoutConstraint.activate([ + showEmbedButton.centerXAnchor.constraint(equalTo: imageView.centerXAnchor), + showEmbedButton.centerYAnchor.constraint(equalTo: imageView.centerYAnchor), + ]) + + addInteraction(UIContextMenuInteraction(delegate: self)) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public func configure(card: Card) { + if let host = card.url?.host { + accessibilityLabel = "\(card.title) \(host)" + } else { + accessibilityLabel = card.title + } + + titleLabel.text = card.title + linkLabel.text = card.url?.host + imageView.contentMode = .center + + imageView.sd_setImage( + with: card.imageURL, + placeholderImage: icon(for: card.layout) + ) { [weak self] image, _, _, _ in + if image != nil { + self?.imageView.contentMode = .scaleAspectFill + } + + self?.containerStackView.setNeedsLayout() + self?.containerStackView.layoutIfNeeded() + } + + if let html = card.html, !html.isEmpty { + showEmbedButton.isHidden = false + self.html = html + } else { + webView?.removeFromSuperview() + webView = nil + showEmbedButton.isHidden = true + self.html = "" + } + + updateConstraints(for: card.layout) + } + + public override func didMoveToWindow() { + super.didMoveToWindow() + + if let window = window { + layer.borderWidth = window.screen.pixelSize + dividerConstraint?.constant = window.screen.pixelSize + } + } + + private func updateConstraints(for layout: Layout) { + guard layout != self.layout else { return } + self.layout = layout + + NSLayoutConstraint.deactivate(layoutConstraints) + dividerConstraint?.deactivate() + + let pixelSize = (window?.screen.pixelSize ?? 1) + switch layout { + case .large(let aspectRatio): + containerStackView.alignment = .fill + containerStackView.axis = .vertical + layoutConstraints = [ + imageView.widthAnchor.constraint( + equalTo: imageView.heightAnchor, + multiplier: aspectRatio + ) + // This priority is important or constraints break; + // it still renders the card correctly. + .priority(.defaultLow - 1), + // set a reasonable max height for very tall images + imageView.heightAnchor + .constraint(lessThanOrEqualToConstant: 400), + ] + dividerConstraint = dividerView.heightAnchor.constraint(equalToConstant: pixelSize).activate() + case .compact: + containerStackView.alignment = .center + containerStackView.axis = .horizontal + layoutConstraints = [ + imageView.heightAnchor.constraint(equalTo: heightAnchor), + imageView.widthAnchor.constraint(equalToConstant: 85), + heightAnchor.constraint(equalToConstant: 85).priority(.defaultLow - 1), + heightAnchor.constraint(greaterThanOrEqualToConstant: 85), + dividerView.heightAnchor.constraint(equalTo: containerStackView.heightAnchor), + ] + dividerConstraint = dividerView.widthAnchor.constraint(equalToConstant: pixelSize).activate() + } + + NSLayoutConstraint.activate(layoutConstraints) + } + + private func icon(for layout: Layout) -> UIImage? { + switch layout { + case .compact: + return UIImage(systemName: "newspaper.fill") + case .large: + let configuration = UIImage.SymbolConfiguration(pointSize: 32) + return UIImage(systemName: "photo", withConfiguration: configuration) + } + } + + private func apply(theme: Theme) { + layer.borderColor = theme.separator.cgColor + dividerView.backgroundColor = theme.separator + imageView.backgroundColor = UIColor.tertiarySystemFill + } +} + +// MARK: WKWebView delegates +extension StatusCardControl: WKNavigationDelegate, WKUIDelegate { + fileprivate func showWebView() { + let webView = setupWebView() + webView.loadHTMLString("" + html, baseURL: nil) + if webView.superview == nil { + addSubview(webView) + webView.pinTo(to: imageView) + } + } + + private func setupWebView() -> WKWebView { + if let webView { return webView } + + let config = WKWebViewConfiguration() + config.processPool = Self.cardContentPool + config.websiteDataStore = .nonPersistent() // private/incognito mode + config.suppressesIncrementalRendering = true + config.allowsInlineMediaPlayback = true + let webView = WKWebView(frame: .zero, configuration: config) + webView.uiDelegate = self + webView.navigationDelegate = self + webView.translatesAutoresizingMaskIntoConstraints = false + webView.isOpaque = false + webView.backgroundColor = .clear + self.webView = webView + return webView + } + + public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy { + let isTopLevelNavigation: Bool + if let frame = navigationAction.targetFrame { + isTopLevelNavigation = frame.isMainFrame + } else { + isTopLevelNavigation = true + } + + if isTopLevelNavigation, + // ignore form submits and such + navigationAction.navigationType == .linkActivated || navigationAction.navigationType == .other, + let url = navigationAction.request.url, + url.absoluteString != "about:blank" { + delegate?.statusCardControl(self, didTapURL: url) + return .cancel + } + return .allow + } + + public func webViewDidClose(_ webView: WKWebView) { + webView.removeFromSuperview() + self.webView = nil + } +} + +// MARK: UIContextMenuInteractionDelegate +extension StatusCardControl { + public override func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? { + return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { elements in + self.delegate?.statusCardControlMenu(self) + } + } + + public override func contextMenuInteraction(_ interaction: UIContextMenuInteraction, previewForDismissingMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { + UITargetedPreview(view: self) + } +} + +private extension StatusCardControl { + enum Layout: Equatable { + case compact + case large(aspectRatio: CGFloat) + } +} + +private extension Card { + var layout: StatusCardControl.Layout { + var aspectRatio = CGFloat(width) / CGFloat(height) + if !aspectRatio.isFinite { + aspectRatio = 1 + } + return (abs(aspectRatio - 1) < 0.05 || image == nil) && html == nil + ? .compact + : .large(aspectRatio: aspectRatio) + } +} + +private extension UILayoutPriority { + static let zero = UILayoutPriority(rawValue: 0) +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift index 47e4f18ff..6e950bc95 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+Configuration.swift @@ -53,8 +53,20 @@ extension StatusView { configureContent(status: status) configureMedia(status: status) configurePoll(status: status) + configureCard(status: status) configureToolbar(status: status) configureFilter(status: status) + viewModel.originalStatus = status + [ + status.publisher(for: \.translatedContent), + status.reblog?.publisher(for: \.translatedContent) + ].compactMap { $0 } + .last? + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + self?.configureTranslated(status: status) + } + .store(in: &disposeBag) } } @@ -231,7 +243,50 @@ extension StatusView { .store(in: &disposeBag) } + func revertTranslation() { + guard let originalStatus = viewModel.originalStatus else { return } + viewModel.translatedFromLanguage = nil + viewModel.translatedUsingProvider = nil + originalStatus.reblog?.update(translatedContent: nil) + originalStatus.update(translatedContent: nil) + configure(status: originalStatus) + } + + func configureTranslated(status: Status) { + let translatedContent: Status.TranslatedContent? = { + if let translatedContent = status.reblog?.translatedContent { + return translatedContent + } + return status.translatedContent + + }() + + guard + let translatedContent = translatedContent + else { + viewModel.isCurrentlyTranslating = false + return + } + + // content + do { + let content = MastodonContent(content: translatedContent.content, emojis: status.emojis.asDictionary) + let metaContent = try MastodonMetaContent.convert(document: content) + viewModel.content = metaContent + viewModel.translatedFromLanguage = status.reblog?.language ?? status.language + viewModel.translatedUsingProvider = status.reblog?.translatedContent?.provider ?? status.translatedContent?.provider + viewModel.isCurrentlyTranslating = false + } catch { + assertionFailure(error.localizedDescription) + viewModel.content = PlaintextMetaContent(string: "") + } + } + private func configureContent(status: Status) { + guard status.translatedContent == nil else { + return configureTranslated(status: status) + } + let status = status.reblog ?? status // spoilerText @@ -254,6 +309,8 @@ extension StatusView { let content = MastodonContent(content: status.content, emojis: status.emojis.asDictionary) let metaContent = try MastodonMetaContent.convert(document: content) viewModel.content = metaContent + viewModel.translatedFromLanguage = nil + viewModel.isCurrentlyTranslating = false } catch { assertionFailure(error.localizedDescription) viewModel.content = PlaintextMetaContent(string: "") @@ -349,6 +406,17 @@ extension StatusView { .assign(to: \.isVoting, on: viewModel) .store(in: &disposeBag) } + + private func configureCard(status: Status) { + let status = status.reblog ?? status + if viewModel.mediaViewConfigurations.isEmpty { + status.publisher(for: \.card) + .assign(to: \.card, on: viewModel) + .store(in: &disposeBag) + } else { + viewModel.card = nil + } + } private func configureToolbar(status: Status) { let status = status.reblog ?? status diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift index 9fef7b3d9..fa16e50e0 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift @@ -17,6 +17,7 @@ import MastodonCommon import MastodonExtension import MastodonLocalization import MastodonSDK +import MastodonMeta extension StatusView { public final class ViewModel: ObservableObject { @@ -26,8 +27,10 @@ extension StatusView { let logger = Logger(subsystem: "StatusView", category: "ViewModel") + public var context: AppContext? public var authContext: AuthContext? - + public var originalStatus: Status? + // Header @Published public var header: Header = .none @@ -43,6 +46,11 @@ extension StatusView { @Published public var isMuting = false @Published public var isBlocking = false + // Translation + @Published public var isCurrentlyTranslating = false + @Published public var translatedFromLanguage: String? + @Published public var translatedUsingProvider: String? + @Published public var timestamp: Date? public var timestampFormatter: ((_ date: Date) -> String)? @Published public var timestampText = "" @@ -69,7 +77,10 @@ extension StatusView { @Published public var voteCount = 0 @Published public var expireAt: Date? @Published public var expired: Bool = false - + + // Card + @Published public var card: Card? + // Visibility @Published public var visibility: MastodonVisibility = .public @@ -134,6 +145,9 @@ extension StatusView { isContentSensitive = false isMediaSensitive = false isSensitiveToggled = false + translatedFromLanguage = nil + translatedUsingProvider = nil + isCurrentlyTranslating = false activeFilters = [] filterContext = nil @@ -146,14 +160,12 @@ extension StatusView { $isMyself ) .map { visibility, isMyself in - if isMyself { - return true - } - switch visibility { - case .public, .unlisted: + case .public, .unlisted, ._other: return true - case .private, .direct, ._other: + case .private where isMyself: + return true + case .private, .direct: return false } } @@ -185,6 +197,7 @@ extension StatusView.ViewModel { bindContent(statusView: statusView) bindMedia(statusView: statusView) bindPoll(statusView: statusView) + bindCard(statusView: statusView) bindToolbar(statusView: statusView) bindMetric(statusView: statusView) bindMenu(statusView: statusView) @@ -299,18 +312,22 @@ extension StatusView.ViewModel { } statusView.contentMetaText.paragraphStyle = paragraphStyle - if let content = content { + if let content = content, !(content.string.isEmpty && content.entities.isEmpty) { statusView.contentMetaText.configure( content: content ) statusView.contentMetaText.textView.accessibilityTraits = [.staticText] statusView.contentMetaText.textView.accessibilityElementsHidden = false + statusView.contentMetaText.textView.isHidden = false + } else { statusView.contentMetaText.reset() statusView.contentMetaText.textView.accessibilityLabel = "" + statusView.contentMetaText.textView.isHidden = true } statusView.contentMetaText.textView.alpha = isContentReveal ? 1 : 0 // keep the frame size and only display when revealing + statusView.statusCardControl.alpha = isContentReveal ? 1 : 0 statusView.setSpoilerOverlayViewHidden(isHidden: isContentReveal) @@ -404,12 +421,7 @@ extension StatusView.ViewModel { var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) snapshot.appendItems(items, toSection: .main) - if #available(iOS 15.0, *) { - statusView.pollTableViewDiffableDataSource?.applySnapshotUsingReloadData(snapshot) - } else { - // Fallback on earlier versions - statusView.pollTableViewDiffableDataSource?.apply(snapshot, animatingDifferences: false) - } + statusView.pollTableViewDiffableDataSource?.applySnapshotUsingReloadData(snapshot) statusView.pollTableViewHeightLayoutConstraint.constant = CGFloat(items.count) * PollOptionTableViewCell.height statusView.setPollDisplay() @@ -456,7 +468,7 @@ extension StatusView.ViewModel { pollCountdownDescription ) .sink { pollVoteDescription, pollCountdownDescription in - statusView.pollVoteCountLabel.text = pollVoteDescription + statusView.pollVoteCountLabel.text = pollVoteDescription statusView.pollCountdownLabel.text = pollCountdownDescription ?? "-" } .store(in: &disposeBag) @@ -480,6 +492,15 @@ extension StatusView.ViewModel { .assign(to: \.isEnabled, on: statusView.pollVoteButton) .store(in: &disposeBag) } + + private func bindCard(statusView: StatusView) { + $card.sink { card in + guard let card = card else { return } + statusView.statusCardControl.configure(card: card) + statusView.setStatusCardControlDisplay() + } + .store(in: &disposeBag) + } private func bindToolbar(statusView: StatusView) { $replyCount @@ -581,26 +602,52 @@ extension StatusView.ViewModel { $isBlocking, $isBookmark ) + let publishersThree = Publishers.CombineLatest( + $translatedFromLanguage, + $language + ) - Publishers.CombineLatest( + Publishers.CombineLatest3( publisherOne.eraseToAnyPublisher(), - publishersTwo.eraseToAnyPublisher() + publishersTwo.eraseToAnyPublisher(), + publishersThree.eraseToAnyPublisher() ).eraseToAnyPublisher() - .sink { tupleOne, tupleTwo in + .sink { tupleOne, tupleTwo, tupleThree in let (authorName, isMyself) = tupleOne let (isMuting, isBlocking, isBookmark) = tupleTwo - + let (translatedFromLanguage, language) = tupleThree + guard let name = authorName?.string else { statusView.authorView.menuButton.menu = nil return } + lazy var instanceConfigurationV2: Mastodon.Entity.V2.Instance.Configuration? = { + guard + let context = self.context, + let authContext = self.authContext + else { + return nil + } + + var configuration: Mastodon.Entity.V2.Instance.Configuration? = nil + context.managedObjectContext.performAndWait { + guard let authentication = authContext.mastodonAuthenticationBox.authenticationRecord.object(in: context.managedObjectContext) + else { return } + configuration = authentication.instance?.configurationV2 + } + return configuration + }() + let menuContext = StatusAuthorView.AuthorMenuContext( name: name, isMuting: isMuting, isBlocking: isBlocking, isMyself: isMyself, - isBookmarking: isBookmark + isBookmarking: isBookmark, + isTranslationEnabled: instanceConfigurationV2?.translation?.enabled == true, + isTranslated: translatedFromLanguage != nil, + statusLanguage: language ) let (menu, actions) = authorView.setupAuthorMenu(menuContext: menuContext) authorView.menuButton.menu = menu @@ -726,7 +773,48 @@ extension StatusView.ViewModel { return L10n.Plural.Count.media(count) } - // TODO: Toolbar + let replyLabel = $replyCount + .map { [L10n.Common.Controls.Actions.reply, L10n.Plural.Count.reply($0)] } + .map { $0.joined(separator: ", ") } + + let reblogLabel = Publishers.CombineLatest($isReblog, $reblogCount) + .map { isReblog, reblogCount in + [ + isReblog ? L10n.Common.Controls.Status.Actions.unreblog : L10n.Common.Controls.Status.Actions.reblog, + L10n.Plural.Count.reblog(reblogCount) + ] + } + .map { $0.joined(separator: ", ") } + + let favoriteLabel = Publishers.CombineLatest($isFavorite, $favoriteCount) + .map { isFavorite, favoriteCount in + [ + isFavorite ? L10n.Common.Controls.Status.Actions.unfavorite : L10n.Common.Controls.Status.Actions.favorite, + L10n.Plural.Count.favorite(favoriteCount) + ] + } + .map { $0.joined(separator: ", ") } + + Publishers.CombineLatest4(replyLabel, reblogLabel, $isReblogEnabled, favoriteLabel) + .map { replyLabel, reblogLabel, canReblog, favoriteLabel in + let toolbar = statusView.actionToolbarContainer + let replyAction = UIAccessibilityCustomAction(name: replyLabel) { _ in + statusView.actionToolbarContainer(toolbar, buttonDidPressed: toolbar.replyButton, action: .reply) + return true + } + let reblogAction = UIAccessibilityCustomAction(name: reblogLabel) { _ in + statusView.actionToolbarContainer(toolbar, buttonDidPressed: toolbar.reblogButton, action: .reblog) + return true + } + let favoriteAction = UIAccessibilityCustomAction(name: favoriteLabel) { _ in + statusView.actionToolbarContainer(toolbar, buttonDidPressed: toolbar.favoriteButton, action: .like) + return true + } + // (share, bookmark are excluded since they are already present in the “…” menu action set) + return canReblog ? [replyAction, reblogAction, favoriteAction] : [replyAction, favoriteAction] + } + .assign(to: \.toolbarActions, on: statusView) + .store(in: &disposeBag) Publishers.CombineLatest3( shortAuthorAccessibilityLabel, diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index 30f62eaf7..b2e5a49ae 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -23,6 +23,7 @@ public protocol StatusViewDelegate: AnyObject { func statusView(_ statusView: StatusView, authorAvatarButtonDidPressed button: AvatarButton) func statusView(_ statusView: StatusView, contentSensitiveeToggleButtonDidPressed button: UIButton) func statusView(_ statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta) + func statusView(_ statusView: StatusView, didTapCardWithURL url: URL) func statusView(_ statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaView: MediaView, didSelectMediaViewAt index: Int) func statusView(_ statusView: StatusView, pollTableView tableView: UITableView, didSelectRowAt indexPath: IndexPath) func statusView(_ statusView: StatusView, pollVoteButtonPressed button: UIButton) @@ -32,6 +33,8 @@ public protocol StatusViewDelegate: AnyObject { func statusView(_ statusView: StatusView, mediaGridContainerView: MediaGridContainerView, mediaSensitiveButtonDidPressed button: UIButton) func statusView(_ statusView: StatusView, statusMetricView: StatusMetricView, reblogButtonDidPressed button: UIButton) func statusView(_ statusView: StatusView, statusMetricView: StatusMetricView, favoriteButtonDidPressed button: UIButton) + func statusView(_ statusView: StatusView, cardControl: StatusCardControl, didTapURL url: URL) + func statusView(_ statusView: StatusView, cardControlMenu: StatusCardControl) -> UIMenu? // a11y func statusView(_ statusView: StatusView, accessibilityActivate: Void) @@ -49,7 +52,10 @@ public final class StatusView: UIView { public weak var delegate: StatusViewDelegate? public private(set) var style: Style? - + + // accessibility actions + var toolbarActions = [UIAccessibilityCustomAction]() + public private(set) lazy var viewModel: ViewModel = { let viewModel = ViewModel() viewModel.bind(statusView: self) @@ -113,6 +119,8 @@ public final class StatusView: UIView { ] return metaText }() + + public let statusCardControl = StatusCardControl() // content warning public let spoilerOverlayView = SpoilerOverlayView() @@ -176,6 +184,55 @@ public final class StatusView: UIView { indicatorView.stopAnimating() return indicatorView }() + let isTranslatingLoadingView: UIActivityIndicatorView = { + let activityIndicatorView = UIActivityIndicatorView(style: .medium) + activityIndicatorView.hidesWhenStopped = true + activityIndicatorView.stopAnimating() + return activityIndicatorView + }() + private let translatedInfoLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .regular)) + label.textColor = Asset.Colors.Label.secondary.color + label.numberOfLines = 0 + return label + }() + lazy var translatedInfoView: UIView = { + let containerView = UIView() + + let revertButton = UIButton() + revertButton.titleLabel?.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .bold)) + revertButton.setTitle(L10n.Common.Controls.Status.Translation.showOriginal, for: .normal) + revertButton.setTitleColor(Asset.Colors.brand.color, for: .normal) + revertButton.addAction(UIAction { [weak self] _ in + self?.revertTranslation() + }, for: .touchUpInside) + + [containerView, translatedInfoLabel, revertButton].forEach { + $0.translatesAutoresizingMaskIntoConstraints = false + } + + [translatedInfoLabel, revertButton].forEach { + containerView.addSubview($0) + } + + translatedInfoLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + revertButton.setContentHuggingPriority(.required, for: .horizontal) + + NSLayoutConstraint.activate([ + containerView.heightAnchor.constraint(equalToConstant: 24), + translatedInfoLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor), + translatedInfoLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 16), + translatedInfoLabel.trailingAnchor.constraint(equalTo: revertButton.leadingAnchor, constant: -16), + revertButton.topAnchor.constraint(equalTo: containerView.topAnchor), + revertButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -16), + revertButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor) + ]) + + containerView.isHidden = true + + return containerView + }() // toolbar let actionToolbarAdaptiveMarginContainerView = AdaptiveMarginContainerView() @@ -203,12 +260,7 @@ public final class StatusView: UIView { authorView.avatarButton.avatarImageView.cancelTask() if var snapshot = pollTableViewDiffableDataSource?.snapshot() { snapshot.deleteAllItems() - if #available(iOS 15.0, *) { - pollTableViewDiffableDataSource?.applySnapshotUsingReloadData(snapshot) - } else { - // Fallback on earlier versions - pollTableViewDiffableDataSource?.apply(snapshot, animatingDifferences: false) - } + pollTableViewDiffableDataSource?.applySnapshotUsingReloadData(snapshot) } setHeaderDisplay(isDisplay: false) @@ -217,6 +269,8 @@ public final class StatusView: UIView { setMediaDisplay(isDisplay: false) setPollDisplay(isDisplay: false) setFilterHintLabelDisplay(isDisplay: false) + setStatusCardControlDisplay(isDisplay: false) + setupTranslationIndicator() } public override init(frame: CGRect) { @@ -257,10 +311,14 @@ extension StatusView { // content contentMetaText.textView.delegate = self contentMetaText.textView.linkDelegate = self - + + // card + statusCardControl.addTarget(self, action: #selector(statusCardControlPressed), for: .touchUpInside) + statusCardControl.delegate = self + // media mediaGridContainerView.delegate = self - + // poll pollTableView.translatesAutoresizingMaskIntoConstraints = false pollTableViewHeightLayoutConstraint = pollTableView.heightAnchor.constraint(equalToConstant: 44.0).priority(.required - 1) @@ -295,6 +353,12 @@ extension StatusView { logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") delegate?.statusView(self, spoilerOverlayViewDidPressed: spoilerOverlayView) } + + @objc private func statusCardControlPressed(_ sender: StatusCardControl) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + guard let url = viewModel.card?.url else { return } + delegate?.statusView(self, didTapCardWithURL: url) + } } @@ -370,11 +434,11 @@ extension StatusView.Style { statusView.authorAdaptiveMarginContainerView.margin = StatusView.containerLayoutMargin statusView.containerStackView.addArrangedSubview(statusView.authorAdaptiveMarginContainerView) - // content container: V - [ contentMetaText ] + // content container: V - [ contentMetaText statusCardControl ] statusView.contentContainer.axis = .vertical statusView.contentContainer.spacing = 12 statusView.contentContainer.distribution = .fill - statusView.contentContainer.alignment = .top + statusView.contentContainer.alignment = .fill statusView.contentAdaptiveMarginContainerView.contentView = statusView.contentContainer statusView.contentAdaptiveMarginContainerView.margin = StatusView.containerLayoutMargin @@ -384,7 +448,11 @@ extension StatusView.Style { // status content statusView.contentContainer.addArrangedSubview(statusView.contentMetaText.textView) - statusView.containerStackView.setCustomSpacing(16, after: statusView.contentMetaText.textView) + statusView.contentContainer.addArrangedSubview(statusView.statusCardControl) + + // translated info + statusView.containerStackView.addArrangedSubview(statusView.isTranslatingLoadingView) + statusView.containerStackView.addArrangedSubview(statusView.translatedInfoView) statusView.spoilerOverlayView.translatesAutoresizingMaskIntoConstraints = false statusView.containerStackView.addSubview(statusView.spoilerOverlayView) @@ -424,7 +492,7 @@ extension StatusView.Style { statusView.pollStatusDotLabel.setContentHuggingPriority(.defaultHigh + 1, for: .horizontal) statusView.pollCountdownLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) statusView.pollVoteButton.setContentHuggingPriority(.defaultHigh + 3, for: .horizontal) - + // action toolbar statusView.actionToolbarAdaptiveMarginContainerView.contentView = statusView.actionToolbarContainer statusView.actionToolbarAdaptiveMarginContainerView.margin = StatusView.containerLayoutMargin @@ -472,6 +540,7 @@ extension StatusView.Style { statusView.headerAdaptiveMarginContainerView.removeFromSuperview() statusView.authorAdaptiveMarginContainerView.removeFromSuperview() + statusView.statusCardControl.removeFromSuperview() } func notificationQuote(statusView: StatusView) { @@ -480,6 +549,7 @@ extension StatusView.Style { statusView.contentAdaptiveMarginContainerView.bottomLayoutConstraint?.constant = 16 // fix bottom margin missing issue statusView.pollAdaptiveMarginContainerView.bottomLayoutConstraint?.constant = 16 // fix bottom margin missing issue statusView.actionToolbarAdaptiveMarginContainerView.removeFromSuperview() + statusView.statusCardControl.removeFromSuperview() } func composeStatusReplica(statusView: StatusView) { @@ -525,6 +595,10 @@ extension StatusView { func setFilterHintLabelDisplay(isDisplay: Bool = true) { filterHintLabel.isHidden = !isDisplay } + + func setStatusCardControlDisplay(isDisplay: Bool = true) { + statusCardControl.isHidden = !isDisplay + } // container width public var contentMaxLayoutWidth: CGFloat { @@ -535,7 +609,11 @@ extension StatusView { extension StatusView { public override var accessibilityCustomActions: [UIAccessibilityCustomAction]? { - get { contentMetaText.textView.accessibilityCustomActions } + get { + (contentMetaText.textView.accessibilityCustomActions ?? []) + + toolbarActions + + (authorView.accessibilityCustomActions ?? []) + } set { } } } @@ -650,6 +728,52 @@ extension StatusView: MastodonMenuDelegate { } } +extension StatusView { + func setupTranslationIndicator() { + viewModel.$isCurrentlyTranslating + .receive(on: DispatchQueue.main) + .sink { [weak self] isTranslating in + switch isTranslating { + case true: + self?.isTranslatingLoadingView.startAnimating() + case false: + self?.isTranslatingLoadingView.stopAnimating() + } + } + .store(in: &disposeBag) + + Publishers.CombineLatest( + viewModel.$translatedFromLanguage, + viewModel.$translatedUsingProvider + ) + .receive(on: DispatchQueue.main) + .sink { [weak self] translatedFromLanguage, translatedUsingProvider in + guard let self = self else { return } + if let translatedFromLanguage = translatedFromLanguage { + self.translatedInfoLabel.text = L10n.Common.Controls.Status.Translation.translatedFrom( + Locale.current.localizedString(forIdentifier: translatedFromLanguage) ?? L10n.Common.Controls.Status.Translation.unknownLanguage, + translatedUsingProvider ?? L10n.Common.Controls.Status.Translation.unknownProvider + ) + self.translatedInfoView.isHidden = false + } else { + self.translatedInfoView.isHidden = true + } + } + .store(in: &disposeBag) + } +} + +// MARK: StatusCardControlDelegate +extension StatusView: StatusCardControlDelegate { + public func statusCardControl(_ statusCardControl: StatusCardControl, didTapURL url: URL) { + delegate?.statusView(self, cardControl: statusCardControl, didTapURL: url) + } + + public func statusCardControlMenu(_ statusCardControl: StatusCardControl) -> UIMenu? { + delegate?.statusView(self, cardControlMenu: statusCardControl) + } +} + #if DEBUG import SwiftUI diff --git a/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift index 446b4af2a..ccb59157a 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift @@ -9,6 +9,7 @@ import os.log import UIKit import MastodonAsset import MastodonLocalization +import MastodonExtension public protocol ActionToolbarContainerDelegate: AnyObject { func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, buttonDidPressed button: UIButton, action: ActionToolbarContainer.Action) @@ -105,7 +106,7 @@ extension ActionToolbarContainer { shareButton.setImage(ActionToolbarContainer.shareImage, for: .normal) container.axis = .horizontal - container.distribution = .fill + container.distribution = .equalSpacing replyButton.translatesAutoresizingMaskIntoConstraints = false reblogButton.translatesAutoresizingMaskIntoConstraints = false @@ -283,7 +284,7 @@ extension ActionToolbarContainer { extension ActionToolbarContainer { private static func title(from number: Int?) -> String { guard let number = number, number > 0 else { return "" } - return String(number) + return number.asAbbreviatedCountString() } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardMeterView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardMeterView.swift index 0c9d243c2..08f84da33 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardMeterView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardMeterView.swift @@ -29,7 +29,6 @@ public final class ProfileStatusDashboardMeterView: UIView { let label = UILabel() label.font = .systemFont(ofSize: 13, weight: .regular) label.textColor = Asset.Colors.Label.primary.color - label.text = L10n.Scene.Profile.Dashboard.posts label.textAlignment = .center if UIView.isZoomedMode { label.adjustsFontSizeToFitWidth = true diff --git a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift index a45e8ef6a..3be447292 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift @@ -66,10 +66,6 @@ extension ProfileStatusDashboardView { containerStackView.setCustomSpacing(spacing + 2, after: followingDashboardMeterView) containerStackView.addArrangedSubview(followersDashboardMeterView) - postDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.posts - followingDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.following - followersDashboardMeterView.textLabel.text = L10n.Scene.Profile.Dashboard.followers - [postDashboardMeterView, followingDashboardMeterView, followersDashboardMeterView].forEach { meterView in let tapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer tapGestureRecognizer.addTarget(self, action: #selector(ProfileStatusDashboardView.tapGestureRecognizerHandler(_:))) diff --git a/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift b/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift index 422494328..6fd5df772 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Menu/MastodonMenu.swift @@ -40,6 +40,7 @@ public enum MastodonMenu { extension MastodonMenu { public enum Action { + case translateStatus(TranslateStatusActionContext) case muteUser(MuteUserActionContext) case blockUser(BlockUserActionContext) case reportUser(ReportUserActionContext) @@ -126,6 +127,15 @@ extension MastodonMenu { delegate.menuAction(self) } return deleteAction + case let .translateStatus(context): + let translateAction = BuiltAction( + title: L10n.Common.Controls.Actions.TranslatePost.title(Locale.current.localizedString(forIdentifier: context.language) ?? L10n.Common.Controls.Actions.TranslatePost.unknownLanguage), + image: UIImage(systemName: "character.book.closed") + ) { [weak delegate] in + guard let delegate = delegate else { return } + delegate.menuAction(self) + } + return translateAction } // end switch } // end func build } // end enum Action @@ -225,4 +235,12 @@ extension MastodonMenu { self.showReblogs = showReblogs } } + + public struct TranslateStatusActionContext { + public let language: String + + public init(language: String) { + self.language = language + } + } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Window/TouchesVisibleWindow.swift b/MastodonSDK/Sources/MastodonUI/View/Window/TouchesVisibleWindow.swift new file mode 100644 index 000000000..8779e1ce7 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Window/TouchesVisibleWindow.swift @@ -0,0 +1,135 @@ +// +// TouchesVisibleWindow.swift +// +// +// Created by Chase Carroll on 12/5/22. +// + +#if DEBUG + +import UIKit + +/// View that represents a single touch from the user. +private final class TouchView: UIView { + + private let blurView = UIVisualEffectView(effect: nil) + + override var frame: CGRect { + didSet { + layer.cornerRadius = frame.height / 2.0 + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + + let isLightMode = traitCollection.userInterfaceStyle == .light + + backgroundColor = .clear + layer.masksToBounds = true + layer.cornerCurve = .circular + layer.borderColor = isLightMode ? UIColor.gray.cgColor : UIColor.white.cgColor + layer.borderWidth = 2.0 + + let blurEffect = isLightMode ? + UIBlurEffect(style: .systemUltraThinMaterialDark) : + UIBlurEffect(style: .systemUltraThinMaterialLight) + blurView.effect = blurEffect + addSubview(blurView) + } + + @available(iOS, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + blurView.frame = bounds + } + +} + + +/// `UIWindow` subclass that renders visual representations of the user's touches. +public final class TouchesVisibleWindow: UIWindow { + + public var touchesVisible = false { + didSet { + if !touchesVisible { + cleanUpAllTouches() + } + } + } + + private var touchViews: [UITouch : TouchView] = [:] + + private func newTouchView() -> TouchView { + let touchSize = 44.0 + return TouchView(frame: CGRect( + origin: .zero, + size: CGSize( + width: touchSize, + height: touchSize + ) + )) + } + + private func cleanupTouch(_ touch: UITouch) { + guard let touchView = touchViews[touch] else { + return + } + + touchView.removeFromSuperview() + touchViews.removeValue(forKey: touch) + } + + private func cleanUpAllTouches() { + for (_, touchView) in touchViews { + touchView.removeFromSuperview() + } + + touchViews.removeAll() + } + + public override func sendEvent(_ event: UIEvent) { + if touchesVisible { + let touches = event.allTouches + + guard + let touches = touches, + touches.count > 0 + else { + cleanUpAllTouches() + super.sendEvent(event) + return + } + + for touch in touches { + let touchLocation = touch.location(in: self) + switch touch.phase { + case .began: + let touchView = newTouchView() + touchView.center = touchLocation + addSubview(touchView) + touchViews[touch] = touchView + + case .moved: + if let touchView = touchViews[touch] { + touchView.center = touchLocation + } + + case .ended, .cancelled: + cleanupTouch(touch) + + default: + break + } + } + } + + super.sendEvent(event) + } +} + +#endif diff --git a/MastodonSDK/Tests/MastodonExtensionTests/IntTests.swift b/MastodonSDK/Tests/MastodonExtensionTests/IntTests.swift new file mode 100644 index 000000000..ec0d045b2 --- /dev/null +++ b/MastodonSDK/Tests/MastodonExtensionTests/IntTests.swift @@ -0,0 +1,53 @@ +// +// IntTests.swift +// +// +// Created by Marcus Kida on 28.12.22. +// + +import XCTest +@testable import MastodonSDK + +class IntFriendlyCountTests: XCTestCase { + func testFriendlyCount_for_1000() { + let input = 1_000 + let expectedOutput = "1K" + + XCTAssertEqual(expectedOutput, input.asAbbreviatedCountString()) + } + + func testFriendlyCount_for_1200() { + let input = 1_200 + let expectedOutput = "1.2K" + + XCTAssertEqual(expectedOutput, input.asAbbreviatedCountString()) + } + + func testFriendlyCount_for_50000() { + let input = 50_000 + let expectedOutput = "50K" + + XCTAssertEqual(expectedOutput, input.asAbbreviatedCountString()) + } + + func testFriendlyCount_for_70666() { + let input = 70_666 + let expectedOutput = "70.7K" + + XCTAssertEqual(expectedOutput, input.asAbbreviatedCountString()) + } + + func testFriendlyCount_for_1M() { + let input = 1_000_000 + let expectedOutput = "1M" + + XCTAssertEqual(expectedOutput, input.asAbbreviatedCountString()) + } + + func testFriendlyCount_for_1dot5M() { + let input = 1_499_000 + let expectedOutput = "1.5M" + + XCTAssertEqual(expectedOutput, input.asAbbreviatedCountString()) + } +} diff --git a/MastodonTests/MastodonTests.swift b/MastodonTests/MastodonTests.swift index b0b64ed96..e26e6a3f1 100644 --- a/MastodonTests/MastodonTests.swift +++ b/MastodonTests/MastodonTests.swift @@ -48,7 +48,6 @@ extension MastodonTests { } } - @available(iOS 15.0, *) func testConnectOnion() async throws { let request = URLRequest( url: URL(string: "http://a232ncr7jexk2chvubaq2v6qdizbocllqap7mnn7w7vrdutyvu32jeyd.onion/@k0gen")!, diff --git a/Podfile b/Podfile index fb0dd1758..5c8a0a47e 100644 --- a/Podfile +++ b/Podfile @@ -1,5 +1,5 @@ source 'https://cdn.cocoapods.org/' -platform :ios, '14.0' +platform :ios, '15.0' inhibit_all_warnings! @@ -14,7 +14,6 @@ target 'Mastodon' do # misc pod 'SwiftGen', '~> 6.6.2' - pod 'DateToolsSwift', '~> 5.0.0' pod 'Kanna', '~> 5.2.2' pod 'Sourcery', '~> 1.6.1' diff --git a/Podfile.lock b/Podfile.lock index d1b5f11a0..f0949d7ab 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,5 +1,4 @@ PODS: - - DateToolsSwift (5.0.0) - FLEX (4.4.1) - Kanna (5.2.7) - Sourcery (1.6.1): @@ -9,7 +8,6 @@ PODS: - XLPagerTabStrip (9.0.0) DEPENDENCIES: - - DateToolsSwift (~> 5.0.0) - FLEX (~> 4.4.0) - Kanna (~> 5.2.2) - Sourcery (~> 1.6.1) @@ -18,7 +16,6 @@ DEPENDENCIES: SPEC REPOS: trunk: - - DateToolsSwift - FLEX - Kanna - Sourcery @@ -26,13 +23,12 @@ SPEC REPOS: - XLPagerTabStrip SPEC CHECKSUMS: - DateToolsSwift: 4207ada6ad615d8dc076323d27037c94916dbfa6 FLEX: 7ca2c8cd3a435ff501ff6d2f2141e9bdc934eaab Kanna: 01cfbddc127f5ff0963692f285fcbc8a9d62d234 Sourcery: f3759f803bd0739f74fc92a4341eed0473ce61ac SwiftGen: 1366a7f71aeef49954ca5a63ba4bef6b0f24138c XLPagerTabStrip: 61c57fd61f611ee5f01ff1495ad6fbee8bf496c5 -PODFILE CHECKSUM: d29eb92012bf66fbd1baad303c44dade1312d897 +PODFILE CHECKSUM: 5b1dbf90a3e6fff01240ad0a2ceb2bc7f7bb4e36 COCOAPODS: 1.11.3 diff --git a/ShareActionExtension/Scene/ShareViewController.swift b/ShareActionExtension/Scene/ShareViewController.swift index 00c5b77de..5804f431b 100644 --- a/ShareActionExtension/Scene/ShareViewController.swift +++ b/ShareActionExtension/Scene/ShareViewController.swift @@ -99,7 +99,8 @@ extension ShareViewController { let composeContentViewModel = ComposeContentViewModel( context: context, authContext: authContext, - kind: .post + destination: .topLevel, + initialContent: "" ) let composeContentViewController = ComposeContentViewController() composeContentViewController.viewModel = composeContentViewModel