Compare commits

...

15 Commits

Author SHA1 Message Date
900094fae4 Export source localization 2023-01-30 16:46:11 -05:00
4fbc9882ce Add LibreTranslate integration for machine translating notes from other languages 2023-01-30 16:46:06 -05:00
William Casarin
2eeeb081fd Merge branch 'translations' 2023-01-30 10:27:44 -08:00
William Casarin
7affc5ae4b Merge remote-tracking branch 'pl_PL' into translations 2023-01-30 10:27:23 -08:00
William Casarin
f283519a0d Merge remote-tracking branch 'de_AT' into translations 2023-01-30 10:27:14 -08:00
William Casarin
3317f23618 Merge remote-tracking branch 'master_de' into translations 2023-01-30 10:24:53 -08:00
2ed17a2509 Add export and import translation scripts
Closes: #430
2023-01-30 10:20:52 -08:00
08ca484d54 Fix height of DM input
Changelog-Fixed: Fixed height of DM input
Closes: #434
2023-01-30 10:19:47 -08:00
transifex-integration[bot]
2feaa207d7 Apply translations in pl_PL
translation completed for the source file '/damus Localizations/en-US.xcloc/Localized Contents/en-US.xliff'
on the 'pl_PL' language.
2023-01-30 17:48:50 +00:00
bb6a09179e Fix bug with copying user pubkey
Co-authored-by: William Casarin <jb55@jb55.com>
Changelog-Fixed: Fixed bug where copying pubkey from context menu only copied your own pubkey
Closes: #425
2023-01-30 09:13:40 -08:00
49f64e7f49 Fix author attribution to the actual translators in CHANGELOG
Closes: #431
2023-01-30 08:59:28 -08:00
a65a6966ac Import de_AT localization 2023-01-29 11:43:07 -05:00
6f15746b8a Replace de-DE localization with de and import into project 2023-01-29 11:41:12 -05:00
transifex-integration[bot]
13066a8fa2 Apply translations in de_AT
translation completed for the source file '/damus Localizations/en-US.xcloc/Localized Contents/en-US.xliff'
on the 'de_AT' language.
2023-01-29 16:17:14 +00:00
transifex-integration[bot]
c647daf9b9 Apply translations in de
translation completed for the source file '/damus Localizations/en-US.xcloc/Localized Contents/en-US.xliff'
on the 'de' language.
2023-01-29 16:07:13 +00:00
42 changed files with 2563 additions and 146 deletions

View File

@@ -2,7 +2,7 @@
### Added
- Added arabic and portugese translations (William Casarin)
- Added Arabic and Portuguese translations (Barodane, Antonio Chagas)
- Add QRCode view for sharing your pubkey (ericholguin)
- Added nostr: uri handling (William Casarin)
@@ -29,7 +29,7 @@
### Added
- Reposts view (Terry Yiu)
- Translations for it_IT, it_CH, fr_FR, de_DE, de_AT and lv_LV (William Casarin)
- Translations for it_IT, it_CH, fr_FR, de_DE, de_AT and lv_LV (Nicolò Carcagnì, Solobalbo, Gregor, Peter Gerstbach, SYX)
- Added ability to block users (William Casarin)
- Added a way to report content (William Casarin)
- Stretchable profile cover header (Swift)
@@ -56,7 +56,7 @@
- Show website on profiles (William Casarin)
- Add the ability to choose participants when replying (Joel Klabo)
- Translations for de_AT, de_DE, tr_TR, fr_FR (William Casarin)
- Translations for de_AT, de_DE, tr_TR, fr_FR (Gregor, Peter Gerstbach, Taylan Benli, Solobalbo)
- Add DM Message Requests (William Casarin)
@@ -76,7 +76,7 @@
- Drastically improved image viewer (OlegAba)
- Added pinch to zoom on images (Swift)
- Add Latin American Spanish translations (William Casarin)
- Add Latin American Spanish translations (Nicolás Valencia)
- Added SVG profile picture support (OlegAba)

View File

@@ -91,15 +91,41 @@ damus implements the following [Nostr Implementation Possibilities][nips]
## Contributing
Contributors welcome! [Email patches][git-send-email] to jb55@jb55.com are preferred, but I accept PRs on github as well.
Contributors welcome!
### Code
[Email patches][git-send-email] to jb55@jb55.com are preferred, but I accept PRs on GitHub as well.
[git-send-email]: http://git-send-email.io
## git log bot
### Translations
npub1fjtdwclt9lspjy8huu3qklr7eklp5uq90u6yh8mec290pqxraccqlufnas
Translators welcome! Join the [Transifex][transifex] project.
### Awards
All user-facing strings must have a comment in order to provide context to translators. If a SwiftUI component has a `comment` parameter, use that. Otherwise, wrap your string with `NSLocalizedString` with the `comment` field populated.
[transifex]: https://explore.transifex.com/damus/damus-ios/
#### Export Source Translations
If user-facing strings have been added or changed, please export them for translation as part of your pull request or commit by running:
```zsh
./devtools/export-source-translation.sh
```
This command will export source translations to `translations/en-US.xcloc/Localized Contents/en-US.xliff`, which the Transifex integration will read from the `master` branch and allow translators to translate those strings.
#### Import Translations
Once 100% of strings have been translated for a given locale, Transifex will open up a pull request with the `translations/<locale>.xliff` file changed. Currently, it must be manually imported into the project before merging the pull request by running:
```zsh
./devtools/import-translation.sh <locale_code_in_snake_case>
```
### Awards
There may be nostr badges awarded for contributors in the future... :)
@@ -107,3 +133,7 @@ First contributors:
1. @randymcmillan
2. @jcarucci27
### git log bot
npub1fjtdwclt9lspjy8huu3qklr7eklp5uq90u6yh8mec290pqxraccqlufnas

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" ?><xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2" xsi:schemaLocation="urn:oasis:names:tc:xliff:document:1.2 http://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd">
<file original="damus/en-US.lproj/InfoPlist.strings" source-language="en-US" target-language="de-DE" datatype="plaintext">
<file original="damus/en-US.lproj/InfoPlist.strings" source-language="en-US" target-language="de" datatype="plaintext">
<header>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="14.2" build-num="14C18"/>
</header>
@@ -24,7 +24,7 @@
</trans-unit>
</body>
</file>
<file original="damus/en-US.lproj/Localizable.strings" source-language="en-US" target-language="de-DE" datatype="plaintext">
<file original="damus/en-US.lproj/Localizable.strings" source-language="en-US" target-language="de" datatype="plaintext">
<header>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="14.2" build-num="14C18"/>
</header>
@@ -45,18 +45,24 @@ Abbreviated version of a nostr public key.</note>
<source>%@ %@</source>
<target>%@ %@</target>
<note>Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.
<note>Sentence composed of 2 variables to describe how many tip payments there are on a post. In source English, the first variable is the number of tip payments, and the second variable is 'Tip' or 'Tips'.
Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.</note>
</trans-unit>
<trans-unit id="%@ has been blocked" xml:space="preserve">
<source>%@ has been blocked</source>
<target>%@ wurde blockiert</target>
<note>Alert message that informs a user was blocked.</note>
</trans-unit>
<trans-unit id="%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." xml:space="preserve">
<source>%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction.</source>
<target>Für das Erstellen eines Accounts ist keine Telefonnumer, E-Mail-Adresse und kein Name notwendig. Lege direkt los!</target>
<target>%@. Ein Konto zu erstellen benötigt keine Telefonnummer, Emailadresse oder Namen. Fang jetzt gleich ganz reibungslos an.</target>
<note>Explanation of what is done to keep personally identifiable information private. There is a heading that precedes this explanation which is a variable to this string.</note>
</trans-unit>
<trans-unit id="%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs" xml:space="preserve">
<source>%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs</source>
<target>%@. Ende-zu-Ende verschlüsselte private Nachrichten. Halte „Big Tech“ aus deinen Direktnachrichten heraus.</target>
<target>%@. End-zu-End verschlüsselter privater Nachrichtenaustausch. Halte Tech-Riesen aus deinen PNs heraus</target>
<note>Explanation of what is done to keep private data encrypted. There is a heading that precedes this explanation which is a variable to this string.</note>
</trans-unit>
@@ -70,7 +76,7 @@ Sentence composed of 2 variables to describe how many profiles a user is followi
<source>%lld</source>
<target>%lld</target>
<note>Number of reposts.
<note>Number of tip payments on a post.
Number of profiles a user is following.</note>
</trans-unit>
<trans-unit id="%lld/%lld" xml:space="preserve">
@@ -93,7 +99,7 @@ Number of profiles a user is following.</note>
</trans-unit>
<trans-unit id="(Profile.displayName(profile: profile, pubkey: whos))'s Followers" xml:space="preserve">
<source>(Profile.displayName(profile: profile, pubkey: whos))'s Followers</source>
<target>(Profile.displayName(profile: profile, pubkey: whos)) Follower</target>
<target>(Profile.displayName(profile: profile, pubkey: whos)) Gefolgte</target>
<note>Navigation bar title for view that shows who is following a user.</note>
</trans-unit>
@@ -133,12 +139,24 @@ Number of profiles a user is following.</note>
<note>Placeholder text for About Me description.</note>
</trans-unit>
<trans-unit id="Accept" xml:space="preserve">
<source>Accept</source>
<target>Zustimmen</target>
<note>Button to accept the end user license agreement before being allowed into the app.</note>
</trans-unit>
<trans-unit id="Account ID" xml:space="preserve">
<source>Account ID</source>
<target>Konto-ID</target>
<note>Label to indicate the public ID of the account.</note>
</trans-unit>
<trans-unit id="Actions" xml:space="preserve">
<source>Actions</source>
<target>Aktionen</target>
<note>Title for confirmation dialog to either share, report, or block a profile.</note>
</trans-unit>
<trans-unit id="Add" xml:space="preserve">
<source>Add</source>
<target>Hinzufügen</target>
@@ -172,7 +190,7 @@ Number of profiles a user is following.</note>
</trans-unit>
<trans-unit id="Banner Image" xml:space="preserve">
<source>Banner Image</source>
<target>Banner Bild</target>
<target>Bannerbild</target>
<note>Label for Banner Image section of user profile form.</note>
</trans-unit>
@@ -200,6 +218,38 @@ Number of profiles a user is following.</note>
<note>Dropdown option label for Lightning wallet, Blixt Wallet</note>
</trans-unit>
<trans-unit id="Block" xml:space="preserve">
<source>Block</source>
<target>Blockieren</target>
<note>Alert button to block a user.
Button to block a profile.
Context menu option for blocking users.</note>
</trans-unit>
<trans-unit id="Block %@?" xml:space="preserve">
<source>Block %@?</source>
<target>%@ blockieren?</target>
<note>Alert message prompt to ask if a user should be blocked.</note>
</trans-unit>
<trans-unit id="Block User" xml:space="preserve">
<source>Block User</source>
<target>Benutzer blockieren</target>
<note>Title of alert for blocking a user.</note>
</trans-unit>
<trans-unit id="Blocked" xml:space="preserve">
<source>Blocked</source>
<target>Blockiert</target>
<note>Sidebar menu label for Profile view.</note>
</trans-unit>
<trans-unit id="Blocked Users" xml:space="preserve">
<source>Blocked Users</source>
<target>Blockierte Benutzer</target>
<note>Navigation title of view to see list of blocked users.</note>
</trans-unit>
<trans-unit id="Blue Wallet" xml:space="preserve">
<source>Blue Wallet</source>
<target>Blue Wallet</target>
@@ -222,7 +272,9 @@ Number of profiles a user is following.</note>
<source>Cancel</source>
<target>Abbrechen</target>
<note>Button to cancel out of posting a note.
<note>Alert button to cancel out of alert for blocking a user.
Button to cancel out of alert that creates a new mutelist.
Button to cancel out of posting a note.
Button to cancel out of reposting a post.
Button to cancel out of view adding user inputted relay.
Cancel out of logging out the user.</note>
@@ -235,7 +287,7 @@ Number of profiles a user is following.</note>
</trans-unit>
<trans-unit id="Chat" xml:space="preserve">
<source>Chat</source>
<target>Unterhaltung</target>
<target>Unterhaltungen</target>
<note>Navigation bar title for Chatroom view.</note>
</trans-unit>
@@ -300,24 +352,36 @@ Number of profiles a user is following.</note>
<note>Context menu option for copying the JSON text from the note.</note>
</trans-unit>
<trans-unit id="Copy Report ID" xml:space="preserve">
<source>Copy Report ID</source>
<target>Meldungs-ID kopieren</target>
<note>Button to copy report ID.</note>
</trans-unit>
<trans-unit id="Copy Text" xml:space="preserve">
<source>Copy Text</source>
<target>Text kopieren</target>
<note>Context menu option for copying the text from an note.</note>
</trans-unit>
<trans-unit id="Copy User ID" xml:space="preserve">
<source>Copy User ID</source>
<target>Benutzer-ID kopieren</target>
<trans-unit id="Copy User Pubkey" xml:space="preserve">
<source>Copy User Pubkey</source>
<target>Öffentlichen Schlüssel des Benutzers kopieren</target>
<note>Context menu option for copying the ID of the user who created the note.</note>
</trans-unit>
<trans-unit id="Copy invoice" xml:space="preserve">
<source>Copy invoice</source>
<target>Rechnung kopieren</target>
<target>Zahlungsdaten kopieren</target>
<note>Title of section for copying a Lightning invoice identifier.</note>
</trans-unit>
<trans-unit id="Could not find user to block..." xml:space="preserve">
<source>Could not find user to block...</source>
<target>Der zu blockierende Benutzer konnte nicht gefunden werden...</target>
<note>Alert message to indicate that the blocked user could not be found.</note>
</trans-unit>
<trans-unit id="Create" xml:space="preserve">
<source>Create</source>
<target>Erstellen</target>
@@ -330,6 +394,12 @@ Number of profiles a user is following.</note>
<note>Button to create an account.</note>
</trans-unit>
<trans-unit id="Create new mutelist" xml:space="preserve">
<source>Create new mutelist</source>
<target>Neue Stummschaltungsliste</target>
<note>Title of alert prompting the user to create a new mutelist.</note>
</trans-unit>
<trans-unit id="Creator(s) of Bitcoin. Absolute legend." xml:space="preserve">
<source>Creator(s) of Bitcoin. Absolute legend.</source>
<target>Erfinder von Bitcoin. Absolute Legende(n).</target>
@@ -338,7 +408,7 @@ Number of profiles a user is following.</note>
</trans-unit>
<trans-unit id="DM Type" xml:space="preserve">
<source>DM Type</source>
<target>PN Art</target>
<target>PN Typ</target>
<note>DM selector for seeing either DMs or message requests, which are messages that have not been responded to yet. DM is the English abbreviation for Direct Message.</note>
</trans-unit>
@@ -365,7 +435,8 @@ Number of profiles a user is following.</note>
<source>Delete</source>
<target>Löschen</target>
<note>Button to delete a relay server that the user connects to.</note>
<note>Button to delete a relay server that the user connects to.
Button to remove a user from their blocklist.</note>
</trans-unit>
<trans-unit id="Dismiss" xml:space="preserve">
<source>Dismiss</source>
@@ -385,6 +456,12 @@ Number of profiles a user is following.</note>
<note>Button to dismiss wallet selection view for paying Lightning invoice.</note>
</trans-unit>
<trans-unit id="EULA" xml:space="preserve">
<source>EULA</source>
<target>Endbenutzer-Lizenzvereinbarung</target>
<note>Label indicating that the below text is the EULA, an acronym for End User License Agreement.</note>
</trans-unit>
<trans-unit id="Earn Money" xml:space="preserve">
<source>Earn Money</source>
<target>Verdiene Geld</target>
@@ -435,13 +512,13 @@ Number of profiles a user is following.</note>
</trans-unit>
<trans-unit id="Followers" xml:space="preserve">
<source>Followers</source>
<target>Follower</target>
<target>Gefolgte:r</target>
<note>Label describing followers of a user.</note>
</trans-unit>
<trans-unit id="Following" xml:space="preserve">
<source>Following</source>
<target>Folgt</target>
<target>Gefolgt</target>
<note>Text to indicate that the button next to it is in a state that indicates that it is in the process of following a profile.
Part of a larger sentence to describe how many profiles a user is following.</note>
@@ -460,7 +537,7 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="Global" xml:space="preserve">
<source>Global</source>
<target>Weltweit</target>
<target>Allgemein</target>
<note>Navigation bar title for Global view where posts from all connected relay servers appear.</note>
</trans-unit>
@@ -482,12 +559,24 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Navigation bar title for Home view where posts and replies appear from those who the user is following.</note>
</trans-unit>
<trans-unit id="Illegal content" xml:space="preserve">
<source>Illegal content</source>
<target>Illegaler Inhalt</target>
<note>Button for user to report that the account or content has illegal content.</note>
</trans-unit>
<trans-unit id="Invalid key" xml:space="preserve">
<source>Invalid key</source>
<target>Ungültiger Schlüssel</target>
<note>Error message indicating that an invalid account key was entered for login.</note>
</trans-unit>
<trans-unit id="It's spam" xml:space="preserve">
<source>It's spam</source>
<target>Es ist Spam</target>
<note>Button for user to report that the account or content has spam.</note>
</trans-unit>
<trans-unit id="LNLink" xml:space="preserve">
<source>LNLink</source>
<target>LNLink</target>
@@ -557,6 +646,12 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Label for NIP-05 Verification section of user profile form.</note>
</trans-unit>
<trans-unit id="No block list found, create a new one? This will overwrite any previous block lists." xml:space="preserve">
<source>No block list found, create a new one? This will overwrite any previous block lists.</source>
<target>Es wurde keine Blockier-Liste gefunden, soll eine neue erzeugt werden? Dies wird eine frühere Blockier-Liste überschreiben.</target>
<note>Alert message prompt that asks if the user wants to create a new block list, overwriting previous block lists.</note>
</trans-unit>
<trans-unit id="Nothing to see here. Check back later!" xml:space="preserve">
<source>Nothing to see here. Check back later!</source>
<target>Hier gibts nichts zu sehen. Schau später wieder vorbei!</target>
@@ -569,6 +664,12 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Navigation title for notifications.</note>
</trans-unit>
<trans-unit id="Nudity or explicit content" xml:space="preserve">
<source>Nudity or explicit content</source>
<target>Nacktheit oder anstößige Inhalte</target>
<note>Button for user to report that the account or content has nudity or explicit content.</note>
</trans-unit>
<trans-unit id="Pay" xml:space="preserve">
<source>Pay</source>
<target>Bezahlen</target>
@@ -665,6 +766,12 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Section title for recommend relay servers that could be added as part of configuration</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>Ablehnen</target>
<note>Button to reject the end user license agreement, which disallows the user from being let into the app.</note>
</trans-unit>
<trans-unit id="Relay" xml:space="preserve">
<source>Relay</source>
<target>Relay</target>
@@ -677,6 +784,12 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Sidebar menu label for Relay servers view</note>
</trans-unit>
<trans-unit id="Relays have been notified and clients will be able to use this information to filter content. Thank you!" xml:space="preserve">
<source>Relays have been notified and clients will be able to use this information to filter content. Thank you!</source>
<target>Relays wurden benachrichtigt und Anwendungen können diese Information nutzen, um Inhalte zu filtern. Vielen Dank!</target>
<note>Description of what was done as a result of sending a report to relay servers.</note>
</trans-unit>
<trans-unit id="Remove all" xml:space="preserve">
<source>Remove all</source>
<target>Alle entfernen</target>
@@ -701,19 +814,44 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Indicating that the user is replying to the following listed people.</note>
</trans-unit>
<trans-unit id="Report" xml:space="preserve">
<source>Report</source>
<target>Melden</target>
<note>Button to report a profile.
Context menu option for reporting content.</note>
</trans-unit>
<trans-unit id="Report ID:" xml:space="preserve">
<source>Report ID:</source>
<target>Meldungs-ID</target>
<note>Label indicating that the text underneath is the identifier of the report that was sent to relay servers.</note>
</trans-unit>
<trans-unit id="Report sent!" xml:space="preserve">
<source>Report sent!</source>
<target>Meldung versandt!</target>
<note>Message indicating that a report was successfully sent to relay servers.</note>
</trans-unit>
<trans-unit id="Repost" xml:space="preserve">
<source>Repost</source>
<target>Teilen</target>
<target>Selbst teilen</target>
<note>Button to confirm reposting a post.
Title of alert for confirming to repost a post.</note>
</trans-unit>
<trans-unit id="Reposted" xml:space="preserve">
<source>Reposted</source>
<target>Geteilt</target>
<target>Selbst geteilt</target>
<note>Text indicating that the post was reposted (i.e. re-shared).</note>
</trans-unit>
<trans-unit id="Reposts" xml:space="preserve">
<source>Reposts</source>
<target>Geteilte Beiträge</target>
<note>Navigation bar title for Reposts view.</note>
</trans-unit>
<trans-unit id="Requests" xml:space="preserve">
<source>Requests</source>
<target>Anfragen</target>
@@ -728,7 +866,7 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="Retry" xml:space="preserve">
<source>Retry</source>
<target>Wiederholung</target>
<target>Erneut versuchen</target>
<note>Button to retry completing account creation after an error occurred.</note>
</trans-unit>
@@ -752,7 +890,7 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="Save Image" xml:space="preserve">
<source>Save Image</source>
<target>Bild speichern</target>
<target>Bild sichern</target>
<note>Context menu option to save an image.</note>
</trans-unit>
@@ -776,7 +914,7 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="Select a Lightning wallet" xml:space="preserve">
<source>Select a Lightning wallet</source>
<target>Wähle eine Lightning-Wallet</target>
<target>Wähle ein Lightning Wallet</target>
<note>Title of section for selecting a Lightning wallet to pay a Lightning invoice.</note>
</trans-unit>
@@ -803,7 +941,8 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<source>Share</source>
<target>Teilen</target>
<note>Button to share an image.</note>
<note>Button to share an image.
Button to share the link to a profile.</note>
</trans-unit>
<trans-unit id="Show" xml:space="preserve">
<source>Show</source>
@@ -829,6 +968,18 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Dropdown option label for Lightning wallet, Strike.</note>
</trans-unit>
<trans-unit id="Thanks!" xml:space="preserve">
<source>Thanks!</source>
<target>Danke!</target>
<note>Button to close out of alert that informs that the action to block a user was successful.</note>
</trans-unit>
<trans-unit id="They are impersonating someone" xml:space="preserve">
<source>They are impersonating someone</source>
<target>Sie gibt sich für jemand anderen aus</target>
<note>Button for user to report that the account is impersonating someone.</note>
</trans-unit>
<trans-unit id="This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective." xml:space="preserve">
<source>This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective.</source>
<target>Dies ist ein öffentlicher Schlüssel, Du wirst keine Beiträge teilen oder oder auf irgendeine Weise interagieren können. Dies wird genutzt um Kontos aus deren Perspektive zu sehen.</target>
@@ -890,6 +1041,18 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Text to indicate that the button next to it is in a state that will unfollow a profile when tapped.</note>
</trans-unit>
<trans-unit id="User blocked" xml:space="preserve">
<source>User blocked</source>
<target>Benutzer blockiert</target>
<note>Alert message to indicate</note>
</trans-unit>
<trans-unit id="User has been blocked" xml:space="preserve">
<source>User has been blocked</source>
<target>Der Benutzer wurde blockiert</target>
<note>Alert message that informs a user was blocked.</note>
</trans-unit>
<trans-unit id="Username" xml:space="preserve">
<source>Username</source>
<target>Benutzername</target>
@@ -933,12 +1096,30 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Text to welcome user.</note>
</trans-unit>
<trans-unit id="What do you want to report?" xml:space="preserve">
<source>What do you want to report?</source>
<target>Was möchtest du melden?</target>
<note>Header text to prompt user what issue they want to report.</note>
</trans-unit>
<trans-unit id="Yes, Overwrite" xml:space="preserve">
<source>Yes, Overwrite</source>
<target>Ja, überschreiben</target>
<note>Text of button that confirms to overwrite the existing mutelist.</note>
</trans-unit>
<trans-unit id="Your Name" xml:space="preserve">
<source>Your Name</source>
<target>Dein Name</target>
<note>Label for Your Name section of user profile form.</note>
</trans-unit>
<trans-unit id="Your report will be sent to the relays you are connected to" xml:space="preserve">
<source>Your report will be sent to the relays you are connected to</source>
<target>Die Meldung wird an Relays versendet, mit denen du verbunden bist</target>
<note>Footer text to inform user what will happen when the report is submitted.</note>
</trans-unit>
<trans-unit id="Zebedee" xml:space="preserve">
<source>Zebedee</source>
<target>Zebedee</target>
@@ -965,7 +1146,7 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="https://example.com/pic.jpg" xml:space="preserve">
<source>https://example.com/pic.jpg</source>
<target>https://beispiel.de/bild.jpg</target>
<target>https://beispiel.at/bild.jpg</target>
<note>Placeholder example text for profile picture URL.</note>
</trans-unit>
@@ -1061,7 +1242,7 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="wss://some.relay.com" xml:space="preserve">
<source>wss://some.relay.com</source>
<target>wss://irgendein.relay.de</target>
<target>wss://ein.relay.at</target>
<note>Placeholder example for relay server address.</note>
</trans-unit>
@@ -1073,7 +1254,7 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
</body>
</file>
<file original="damus/en-US.lproj/Localizable.stringsdict" source-language="en-US" target-language="de-DE" datatype="plaintext">
<file original="damus/en-US.lproj/Localizable.stringsdict" source-language="en-US" target-language="de" datatype="plaintext">
<header>
<tool tool-id="com.apple.dt.xcode" tool-name="Xcode" tool-version="14.2" build-num="14C18"/>
</header>
@@ -1098,13 +1279,13 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="/followers_count:dict/FOLLOWERS:dict/one:dict/:string" xml:space="preserve">
<source>Follower</source>
<target>Follower</target>
<target>Gefolgte:r</target>
<note>Part of a larger sentence to describe how many people are following a user.</note>
</trans-unit>
<trans-unit id="/followers_count:dict/FOLLOWERS:dict/other:dict/:string" xml:space="preserve">
<source>Followers</source>
<target>Follower</target>
<target>Gefolgte</target>
<note>Part of a larger sentence to describe how many people are following a user.</note>
</trans-unit>
@@ -1158,13 +1339,13 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="/replying_to_one_and_others:dict/OTHERS:dict/one:dict/:string" xml:space="preserve">
<source> &amp; %d other</source>
<target>&amp; %d andere</target>
<target> &amp; %d andere</target>
<note>Label to indicate that the user is replying to 1 user and others.</note>
</trans-unit>
<trans-unit id="/replying_to_one_and_others:dict/OTHERS:dict/other:dict/:string" xml:space="preserve">
<source> &amp; %d others</source>
<target>&amp; %d andere</target>
<target> &amp; %d andere</target>
<note>Label to indicate that the user is replying to 1 user and others.</note>
</trans-unit>
@@ -1180,13 +1361,13 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="/replying_to_two_and_others:dict/OTHERS:dict/one:dict/:string" xml:space="preserve">
<source> &amp; %d other</source>
<target>&amp; %d andere</target>
<target> &amp; %d andere</target>
<note>Label to indicate that the user is replying to 2 users and others.</note>
</trans-unit>
<trans-unit id="/replying_to_two_and_others:dict/OTHERS:dict/other:dict/:string" xml:space="preserve">
<source> &amp; %d others</source>
<target>&amp; %d andere</target>
<target> &amp; %d andere</target>
<note>Label to indicate that the user is replying to 2 users and others.</note>
</trans-unit>
@@ -1202,13 +1383,13 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="/reposts_count:dict/REPOSTS:dict/one:dict/:string" xml:space="preserve">
<source>Repost</source>
<target>Mal geteilt</target>
<target>geteilter Beitrag</target>
<note>Part of a larger sentence to describe how many reposts there are.</note>
</trans-unit>
<trans-unit id="/reposts_count:dict/REPOSTS:dict/other:dict/:string" xml:space="preserve">
<source>Reposts</source>
<target>Mal geteilt</target>
<target>geteilte Beiträge</target>
<note>Part of a larger sentence to describe how many reposts there are.</note>
</trans-unit>

File diff suppressed because it is too large Load Diff

View File

@@ -18,6 +18,7 @@
3ACB685C297633BC00C46468 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685A297633BC00C46468 /* InfoPlist.strings */; };
3ACB685F297633BC00C46468 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685D297633BC00C46468 /* Localizable.strings */; };
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */; };
3AE45AF6297BB2E700C1D842 /* LibreTranslateServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE45AF5297BB2E700C1D842 /* LibreTranslateServer.swift */; };
4C06670128FC7C5900038D2A /* RelayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670028FC7C5900038D2A /* RelayView.swift */; };
4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 4C06670328FC7EC500038D2A /* Kingfisher */; };
4C06670628FCB08600038D2A /* ImageCarousel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C06670528FCB08600038D2A /* ImageCarousel.swift */; };
@@ -230,12 +231,13 @@
3AA247FC297E3CFF0090C62D /* RepostsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepostsModel.swift; sourceTree = "<group>"; };
3AA247FE297E3D900090C62D /* RepostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostsView.swift; sourceTree = "<group>"; };
3AA24801297E3DC20090C62D /* RepostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepostView.swift; sourceTree = "<group>"; };
3AB5B86A2986D8A3006599D2 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = "<group>"; };
3AB5B86B2986D8A3006599D2 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
3AB5B86C2986D8A3006599D2 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = de; path = de.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
3ACB685B297633BC00C46468 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-419"; path = "es-419.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
3ACB685E297633BC00C46468 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-419"; path = "es-419.lproj/Localizable.strings"; sourceTree = "<group>"; };
3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeAgoTests.swift; sourceTree = "<group>"; };
3AEABD20297CCFA8003F2975 /* de-DE */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "de-DE"; path = "de-DE.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
3AEABD21297CCFA8003F2975 /* de-DE */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "de-DE"; path = "de-DE.lproj/Localizable.strings"; sourceTree = "<group>"; };
3AEABD22297CCFA8003F2975 /* de-DE */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "de-DE"; path = "de-DE.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
3AE45AF5297BB2E700C1D842 /* LibreTranslateServer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibreTranslateServer.swift; sourceTree = "<group>"; };
3AEB8003297CCEA800713A25 /* tr-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "tr-TR"; path = "tr-TR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
3AEB8004297CCEA800713A25 /* tr-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "tr-TR"; path = "tr-TR.lproj/Localizable.strings"; sourceTree = "<group>"; };
3AEB8005297CCEA900713A25 /* tr-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "tr-TR"; path = "tr-TR.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
@@ -582,6 +584,7 @@
7C45AE70297353390031D7BC /* KFImageModel.swift */,
4CF0ABD32980996B00D66079 /* Report.swift */,
4CF0ABDD2981A69500D66079 /* MutelistModel.swift */,
3AE45AF5297BB2E700C1D842 /* LibreTranslateServer.swift */,
);
path = Models;
sourceTree = "<group>";
@@ -960,11 +963,11 @@
"es-419",
"en-US",
"de-AT",
"de-DE",
"tr-TR",
"fr-FR",
"lv-LV",
"it-IT",
de,
);
mainGroup = 4CE6DEDA27F7A08100C66700;
packageReferences = (
@@ -1171,6 +1174,7 @@
4C06670B28FDE64700038D2A /* damus.c in Sources */,
4FE60CDD295E1C5E00105A1F /* Wallet.swift in Sources */,
3AA247FF297E3D900090C62D /* RepostsView.swift in Sources */,
3AE45AF6297BB2E700C1D842 /* LibreTranslateServer.swift in Sources */,
4C99737B28C92A9200E53835 /* ChatroomMetadata.swift in Sources */,
4CC7AAF4297F18B400430951 /* ReplyDescription.swift in Sources */,
4C75EFA427FA577B0006080F /* PostView.swift in Sources */,
@@ -1230,11 +1234,11 @@
3A5C4575296A879E0032D398 /* es-419 */,
3A2B8B0A296A8982009CC16D /* en-US */,
3A5EA111297CCF6C00569477 /* de-AT */,
3AEABD22297CCFA8003F2975 /* de-DE */,
3AEB8005297CCEA900713A25 /* tr-TR */,
3A4F3322297CCFEE004B5F72 /* fr-FR */,
3A185A06297F2C3800F4BDC0 /* lv-LV */,
3A929C22297F2CF80090925E /* it-IT */,
3AB5B86C2986D8A3006599D2 /* de */,
);
name = Localizable.stringsdict;
sourceTree = "<group>";
@@ -1244,11 +1248,11 @@
children = (
3ACB685B297633BC00C46468 /* es-419 */,
3A5EA10F297CCF6C00569477 /* de-AT */,
3AEABD20297CCFA8003F2975 /* de-DE */,
3AEB8003297CCEA800713A25 /* tr-TR */,
3A4F3320297CCFEE004B5F72 /* fr-FR */,
3A185A04297F2C3800F4BDC0 /* lv-LV */,
3A929C20297F2CF80090925E /* it-IT */,
3AB5B86A2986D8A3006599D2 /* de */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
@@ -1258,11 +1262,11 @@
children = (
3ACB685E297633BC00C46468 /* es-419 */,
3A5EA110297CCF6C00569477 /* de-AT */,
3AEABD21297CCFA8003F2975 /* de-DE */,
3AEB8004297CCEA800713A25 /* tr-TR */,
3A4F3321297CCFEE004B5F72 /* fr-FR */,
3A185A05297F2C3800F4BDC0 /* lv-LV */,
3A929C21297F2CF80090925E /* it-IT */,
3AB5B86B2986D8A3006599D2 /* de */,
);
name = Localizable.strings;
sourceTree = "<group>";

View File

@@ -34,7 +34,7 @@ struct InvoiceView: View {
let invoice: Invoice
@State var showing_select_wallet: Bool = false
@ObservedObject var user_settings = UserSettingsStore()
@EnvironmentObject var user_settings: UserSettingsStore
var PayButton: some View {
Button {

View File

@@ -292,6 +292,7 @@ struct ContentView: View {
.padding([.bottom], 8)
}
}
.environmentObject(user_settings)
.onAppear() {
self.connect()
//KingfisherManager.shared.cache.clearDiskCache()

View File

@@ -22,7 +22,7 @@ struct DamusState {
var pubkey: String {
return keypair.pubkey
}
var is_privkey_user: Bool {
keypair.privkey != nil
}

View File

@@ -0,0 +1,44 @@
//
// LibreTranslateServer.swift
// damus
//
// Created by Terry Yiu on 1/21/23.
//
import Foundation
enum LibreTranslateServer: String, CaseIterable, Identifiable {
var id: String { self.rawValue }
struct Model: Identifiable, Hashable {
var id: String { self.tag }
var tag: String
var displayName: String
var url: String?
}
case none
case argosopentech
case terraprint
case vern
case custom
var model: Model {
switch self {
case .none:
return .init(tag: self.rawValue, displayName: NSLocalizedString("None", comment: "Dropdown option for selecting no translation server."), url: nil)
case .argosopentech:
return .init(tag: self.rawValue, displayName: "translate.argosopentech.com", url: "https://translate.argosopentech.com")
case .terraprint:
return .init(tag: self.rawValue, displayName: "translate.terraprint.co", url: "https://translate.terraprint.co")
case .vern:
return .init(tag: self.rawValue, displayName: "lt.vern.cc", url: "https://lt.vern.cc")
case .custom:
return .init(tag: self.rawValue, displayName: NSLocalizedString("Custom", comment: "Dropdown option for selecting a custom translation server."), url: nil)
}
}
static var allModels: [Model] {
return Self.allCases.map { $0.model }
}
}

View File

@@ -6,6 +6,7 @@
//
import Foundation
import Vault
class UserSettingsStore: ObservableObject {
@Published var default_wallet: Wallet {
@@ -26,6 +27,44 @@ class UserSettingsStore: ObservableObject {
}
}
@Published var libretranslate_server: LibreTranslateServer {
didSet {
if oldValue == libretranslate_server {
return
}
UserDefaults.standard.set(libretranslate_server.rawValue, forKey: "libretranslate_server")
libretranslate_api_key = ""
if libretranslate_server == .custom || libretranslate_server == .none {
libretranslate_url = ""
} else {
libretranslate_url = libretranslate_server.model.url!
}
}
}
@Published var libretranslate_url: String {
didSet {
UserDefaults.standard.set(libretranslate_url, forKey: "libretranslate_url")
}
}
@Published var libretranslate_api_key: String {
didSet {
do {
if libretranslate_api_key == "" {
try clearLibreTranslateApiKey()
} else {
try saveLibreTranslateApiKey(libretranslate_api_key)
}
} catch {
// No-op.
}
}
}
init() {
if let defaultWalletName = UserDefaults.standard.string(forKey: "default_wallet"),
let default_wallet = Wallet(rawValue: defaultWalletName)
@@ -37,5 +76,40 @@ class UserSettingsStore: ObservableObject {
show_wallet_selector = UserDefaults.standard.object(forKey: "show_wallet_selector") as? Bool ?? true
left_handed = UserDefaults.standard.object(forKey: "left_handed") as? Bool ?? false
if let translationServerName = UserDefaults.standard.string(forKey: "libretranslate_server"),
let translationServer = LibreTranslateServer(rawValue: translationServerName) {
self.libretranslate_server = translationServer
libretranslate_url = translationServer.model.url ?? UserDefaults.standard.object(forKey: "libretranslate_url") as? String ?? ""
} else {
// Note from @tyiu:
// Default server is disabled by default for now until we gain some confidence that it is working well in production.
// Instead of throwing all Damus users onto feature immediately, allow for discovery of feature organically.
// Also, we are connecting to servers listed as mirrors on the official LibreTranslate GitHub README that do not require API keys.
// However, we have not asked them for permission to use, so we're trying to be good neighbors for now.
// Opportunity: spin up dedicated trusted LibreTranslate server that requires an API key for any access (or higher rate limit access).
libretranslate_server = .none
libretranslate_url = ""
}
do {
libretranslate_api_key = try Vault.getPrivateKey(keychainConfiguration: DamusLibreTranslateKeychainConfiguration())
} catch {
libretranslate_api_key = ""
}
}
func saveLibreTranslateApiKey(_ apiKey: String) throws {
try Vault.savePrivateKey(apiKey, keychainConfiguration: DamusLibreTranslateKeychainConfiguration())
}
func clearLibreTranslateApiKey() throws {
try Vault.deletePrivateKey(keychainConfiguration: DamusLibreTranslateKeychainConfiguration())
}
}
struct DamusLibreTranslateKeychainConfiguration: KeychainConfiguration {
var serviceName = "damus"
var accessGroup: String? = nil
var accountName = "libretranslate_apikey"
}

View File

@@ -103,11 +103,15 @@ class NostrEvent: Codable, Identifiable, CustomStringConvertible, Equatable, Has
if let bs = _blocks {
return bs
}
let blocks = parse_mentions(content: self.get_content(privkey), tags: self.tags)
let blocks = get_blocks(content: self.get_content(privkey))
self._blocks = blocks
return blocks
}
func get_blocks(content: String) -> [Block] {
return parse_mentions(content: content, tags: self.tags)
}
lazy var inner_event: NostrEvent? = {
// don't try to deserialize an inner event if we know there won't be one
if self.known_kind == .boost {

View File

@@ -24,7 +24,7 @@ struct ChatroomView: View {
next_ev: ind == count-1 ? nil : thread.events[ind+1],
damus_state: damus
)
.event_context_menu(ev, keypair: damus.keypair)
.event_context_menu(ev, privkey: damus.keypair.privkey, pubkey: ev.pubkey)
.onTapGesture {
if thread.initial_event.id == ev.id {
//dismiss()

View File

@@ -15,6 +15,7 @@ struct ConfigView: View {
@State var confirm_logout: Bool = false
@State var new_relay: String = ""
@State var show_privkey: Bool = false
@State var show_libretranslate_api_key: Bool = false
@State var privkey: String
@State var privkey_copied: Bool = false
@State var pubkey_copied: Bool = false
@@ -116,6 +117,39 @@ struct ConfigView: View {
}
}
Section(NSLocalizedString("LibreTranslate Translations", comment: "Section title for selecting the server that hosts the LibreTranslate machine translation API.")) {
Picker(NSLocalizedString("Server", comment: "Prompt selection of LibreTranslate server to perform machine translations on notes"), selection: $user_settings.libretranslate_server) {
ForEach(LibreTranslateServer.allCases, id: \.self) { server in
Text(server.model.displayName)
.tag(server.model.tag)
}
}
if user_settings.libretranslate_server != .none {
TextField(NSLocalizedString("URL", comment: "Example URL to LibreTranslate server"), text: $user_settings.libretranslate_url)
.disableAutocorrection(true)
.disabled(user_settings.libretranslate_server != .custom)
.autocapitalization(UITextAutocapitalizationType.none)
HStack {
if show_libretranslate_api_key {
TextField(NSLocalizedString("API Key (optional)", comment: "Example URL to LibreTranslate server"), text: $user_settings.libretranslate_api_key)
.disableAutocorrection(true)
.autocapitalization(UITextAutocapitalizationType.none)
Button(NSLocalizedString("Hide API Key", comment: "Button to hide the LibreTranslate server API key.")) {
show_libretranslate_api_key = false
}
} else {
SecureField(NSLocalizedString("API Key (optional)", comment: "Example URL to LibreTranslate server"), text: $user_settings.libretranslate_api_key)
.disableAutocorrection(true)
.autocapitalization(UITextAutocapitalizationType.none)
Button(NSLocalizedString("Show API Key", comment: "Button to hide the LibreTranslate server API key.")) {
show_libretranslate_api_key = true
}
}
}
}
}
Section(NSLocalizedString("Left Handed", comment: "Moves the post button to the left side of the screen")) {
Toggle(NSLocalizedString("Left Handed", comment: "Moves the post button to the left side of the screen"), isOn: $user_settings.left_handed)
.toggleStyle(.switch)

View File

@@ -19,7 +19,7 @@ struct DMChatView: View {
VStack(alignment: .leading) {
ForEach(Array(zip(dms.events, dms.events.indices)), id: \.0.id) { (ev, ind) in
DMView(event: dms.events[ind], damus_state: damus_state)
.event_context_menu(ev, keypair: damus_state.keypair)
.event_context_menu(ev, privkey: damus_state.keypair.privkey, pubkey: ev.pubkey)
}
EndBlock(height: 80)
}
@@ -63,6 +63,8 @@ struct DMChatView: View {
)
.padding(16)
.foregroundColor(Color.primary)
.frame(minHeight: 70, maxHeight: 150, alignment: .bottom)
.fixedSize(horizontal: false, vertical: true)
}
@Environment(\.colorScheme) var colorScheme
@@ -97,22 +99,15 @@ struct DMChatView: View {
}
}
}
}
.frame(height: 50 + 20 * CGFloat(text_lines))
}
.fixedSize(horizontal: false, vertical: true)
.frame(minHeight: 70, maxHeight: 150, alignment: .bottom)
var text_lines: Int {
var lines = 1
for c in message {
if lines > 4 {
return lines
}
if c.isNewline {
lines += 1
}
Text(message).opacity(0).padding(.all, 8)
.fixedSize(horizontal: false, vertical: true)
.frame(minHeight: 70, maxHeight: 150, alignment: .bottom)
}
return lines
.fixedSize(horizontal: false, vertical: true)
.frame(minHeight: 70, maxHeight: 150, alignment: .bottom)
}
func send_message() {
@@ -142,12 +137,13 @@ struct DMChatView: View {
Footer
}
Text("Send a message to start the conversation...", comment: "Text prompt for user to send a message to the other user.")
.lineLimit(nil)
.multilineTextAlignment(.center)
.padding(.horizontal, 40)
.opacity(((dms.events.count == 0) ? 1.0 : 0.0))
.foregroundColor(.gray)
.lineLimit(nil)
.multilineTextAlignment(.center)
.padding(.horizontal, 40)
.opacity(((dms.events.count == 0) ? 1.0 : 0.0))
.foregroundColor(.gray)
}
.navigationTitle(NSLocalizedString("DMs", comment: "Navigation title for DMs view, where DM is the English abbreviation for Direct Message."))
.toolbar { Header }

View File

@@ -129,7 +129,7 @@ struct EventView: View {
.id(event.id)
.frame(maxWidth: .infinity, minHeight: PFP_SIZE)
.padding([.bottom], 2)
.event_context_menu(event, keypair: damus.keypair)
.event_context_menu(event, privkey: damus.keypair.privkey, pubkey: pubkey)
}
}
@@ -171,9 +171,9 @@ extension View {
}
}
func event_context_menu(_ event: NostrEvent, keypair: Keypair) -> some View {
func event_context_menu(_ event: NostrEvent, privkey: String?, pubkey: String) -> some View {
return self.contextMenu {
EventMenuContext(event: event, keypair: keypair)
EventMenuContext(event: event, privkey: privkey, pubkey: pubkey)
}
}

View File

@@ -23,7 +23,7 @@ struct EmbeddedEventView: View {
EventBody(damus_state: damus_state, event: event, size: .small)
}
.event_context_menu(event, keypair: damus_state.keypair)
.event_context_menu(event, privkey: damus_state.keypair.privkey, pubkey: pubkey)
}
}

View File

@@ -9,18 +9,19 @@ import SwiftUI
struct EventMenuContext: View {
let event: NostrEvent
let keypair: Keypair
let privkey: String?
let pubkey: String
var body: some View {
Button {
UIPasteboard.general.string = event.get_content(keypair.privkey)
UIPasteboard.general.string = event.get_content(privkey)
} label: {
Label(NSLocalizedString("Copy Text", comment: "Context menu option for copying the text from an note."), systemImage: "doc.on.doc")
}
Button {
UIPasteboard.general.string = keypair.pubkey_bech32
UIPasteboard.general.string = bech32_pubkey(event.pubkey)
} label: {
Label(NSLocalizedString("Copy User Pubkey", comment: "Context menu option for copying the ID of the user who created the note."), systemImage: "person")
}
@@ -44,7 +45,7 @@ struct EventMenuContext: View {
}
// Only allow reporting if logged in with private key and the currently viewed profile is not the logged in profile.
if keypair.pubkey != event.pubkey && keypair.privkey != nil {
if pubkey != event.pubkey && privkey != nil {
Button(role: .destructive) {
let target: ReportTarget = .note(ReportNoteTarget(pubkey: event.pubkey, note_id: event.id))
notify(.report, target)

View File

@@ -49,7 +49,7 @@ struct SelectedEventView: View {
.padding([.top], 4)
}
.padding([.leading], 2)
.event_context_menu(event, keypair: damus.keypair)
.event_context_menu(event, privkey: damus.keypair.privkey, pubkey: event.pubkey)
}
}
}

View File

@@ -8,6 +8,10 @@
import SwiftUI
import LinkPresentation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif
struct NoteArtifacts {
let content: AttributedString
let images: [URL]
@@ -21,6 +25,10 @@ struct NoteArtifacts {
func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -> NoteArtifacts {
let blocks = ev.blocks(privkey)
return render_blocks(blocks: blocks, profiles: profiles, privkey: privkey)
}
func render_blocks(blocks: [Block], profiles: Profiles, privkey: String?) -> NoteArtifacts {
var invoices: [Invoice] = []
var img_urls: [URL] = []
var link_urls: [URL] = []
@@ -47,7 +55,7 @@ func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -
}
}
}
return NoteArtifacts(content: txt, images: img_urls, invoices: invoices, links: link_urls)
}
@@ -64,10 +72,18 @@ struct NoteContentView: View {
let show_images: Bool
@State var checkingTranslationStatus: Bool = false
@State var language: String? = nil
@State var translated_note: String? = nil
@State var show_translated_note: Bool = false
@State var translated_artifacts: NoteArtifacts? = nil
@State var artifacts: NoteArtifacts
@State var preview: LinkViewRepresentable? = nil
let size: EventViewKind
@EnvironmentObject var user_settings: UserSettingsStore
func MainContent() -> some View {
return VStack(alignment: .leading) {
@@ -75,6 +91,29 @@ struct NoteContentView: View {
.font(eventviewsize_to_font(size))
.fixedSize(horizontal: false, vertical: true)
if size == .selected && language != nil && translated_artifacts != nil {
let languageName = Locale.current.localizedString(forLanguageCode: language!)
if show_translated_note {
Button(NSLocalizedString("Translated from \(languageName!)", comment: "Button to indicate that the note has been translated from a different language.")) {
show_translated_note = false
}
.font(.footnote)
.contentShape(Rectangle())
.padding(.top, 10)
Text(translated_artifacts!.content)
.font(eventviewsize_to_font(size))
.fixedSize(horizontal: false, vertical: true)
} else {
Button(NSLocalizedString("Translate Note", comment: "Button to translate note from different language.")) {
show_translated_note = true
}
.font(.footnote)
.contentShape(Rectangle())
.padding(.top, 10)
}
}
if show_images && artifacts.images.count > 0 {
ImageCarousel(urls: artifacts.images)
} else if !show_images && artifacts.images.count > 0 {
@@ -142,6 +181,35 @@ struct NoteContentView: View {
previews.store(evid: self.event.id, preview: view)
self.preview = view
}
if size == .selected && language == nil && !checkingTranslationStatus && user_settings.libretranslate_url != "" {
checkingTranslationStatus = true
let currentLanguage = Locale.current.languageCode ?? "en"
let translator = Translator(user_settings.libretranslate_url, apiKey: user_settings.libretranslate_api_key)
do {
language = try await translator.detect(event.content)
if language == nil {
language = currentLanguage
translated_note = nil
} else if language != currentLanguage {
translated_note = try await translator.translate(event.content, from: language!, to: currentLanguage)
if translated_note != nil {
let blocks = event.get_blocks(content: translated_note!)
translated_artifacts = render_blocks(blocks: blocks, profiles: profiles, privkey: privkey)
}
}
} catch {
// If for whatever reason we're not able to figure out the language of the note, or translate the note, fail gracefully and do not retry. It's not the end of the world. Don't want to take down someone's translation server with an accidental denial of service attack.
language = currentLanguage
translated_note = nil
}
checkingTranslationStatus = false
}
}
}
@@ -196,6 +264,112 @@ func mention_str(_ m: Mention, profiles: Profiles) -> AttributedString {
}
public struct Translator {
private let url: String
private let apiKey: String?
private let session = URLSession.shared
private let encoder = JSONEncoder()
private let decoder = JSONDecoder()
public init(_ url: String, apiKey: String? = nil) {
self.url = url
self.apiKey = apiKey
}
public func detect(_ text: String) async throws -> String? {
let url = try makeURL(path: "/detect")
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
struct RequestBody: Encodable {
let q: String
let api_key: String?
}
let body = RequestBody(q: text, api_key: apiKey)
request.httpBody = try encoder.encode(body)
struct Response: Decodable {
let confidence: Double
let language: String
}
let data = try await session.data(for: request)
let response = try decoder.decode([Response].self, from: data)
let language = response.first!
if language.confidence >= 80 {
return language.language
} else {
return nil
}
}
public func translate(_ text: String, from sourceLanguage: String, to targetLanguage: String) async throws -> String {
let url = try makeURL(path: "/translate")
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
struct RequestBody: Encodable {
let q: String
let source: String
let target: String
let api_key: String?
}
let body = RequestBody(q: text, source: sourceLanguage, target: targetLanguage, api_key: apiKey)
request.httpBody = try encoder.encode(body)
struct Response: Decodable {
let translatedText: String
}
let response: Response = try await decodedData(for: request)
return response.translatedText
}
private func makeURL(path: String) throws -> URL {
guard var components = URLComponents(string: url) else {
throw URLError(.badURL)
}
components.path = path
guard let url = components.url else {
throw URLError(.badURL)
}
return url
}
private func decodedData<Output: Decodable>(for request: URLRequest) async throws -> Output {
let data = try await session.data(for: request)
let result = try decoder.decode(Output.self, from: data)
return result
}
}
private extension URLSession {
func data(for request: URLRequest) async throws -> Data {
var task: URLSessionDataTask?
let onCancel = { task?.cancel() }
return try await withTaskCancellationHandler(
operation: {
try await withCheckedThrowingContinuation { continuation in
task = dataTask(with: request) { data, _, error in
guard let data = data else {
let error = error ?? URLError(.badServerResponse)
return continuation.resume(throwing: error)
}
continuation.resume(returning: data)
}
task?.resume()
}
},
onCancel: { onCancel() }
)
}
}
struct NoteContentView_Previews: PreviewProvider {
static var previews: some View {
let state = test_damus_state()

View File

@@ -115,7 +115,7 @@ struct ProfileView: View {
@State var is_zoomed: Bool = false
@State var show_share_sheet: Bool = false
@State var action_sheet_presented: Bool = false
@StateObject var user_settings = UserSettingsStore()
@EnvironmentObject var user_settings: UserSettingsStore
@Environment(\.dismiss) var dismiss
@Environment(\.colorScheme) var colorScheme

View File

@@ -12,7 +12,7 @@ struct SideMenuView: View {
@Binding var isSidebarVisible: Bool
@State var confirm_logout: Bool = false
@StateObject var user_settings = UserSettingsStore()
@EnvironmentObject var user_settings: UserSettingsStore
@State private var showQRCode = false

View File

@@ -8,7 +8,7 @@
"'%@' is an invalid nip05 identifier. It should look like an email." = "'%@' ist eine ungültige nip05 Kennzeichnung. Diese sollte wie eine Emailadresse aussehen. ";
/* Navigation bar title for view that shows who is following a user. */
"(Profile.displayName(profile: profile, pubkey: whos))'s Followers" = "(Profile.displayName(profile: profile, pubkey: whos)) Follower";
"(Profile.displayName(profile: profile, pubkey: whos))'s Followers" = "(Profile.displayName(profile: profile, pubkey: whos)) Gefolgte";
/* Navigation bar title for view that shows who a user is following. */
"(who) following" = "(who) folgt";
@@ -20,10 +20,13 @@
Abbreviated version of a nostr public key. */
"%@" = "%@";
/* Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.
/* Sentence composed of 2 variables to describe how many tip payments there are on a post. In source English, the first variable is the number of tip payments, and the second variable is 'Tip' or 'Tips'.
Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'. */
"%@ %@" = "%@ %@";
/* Alert message that informs a user was blocked. */
"%@ has been blocked" = "%@ wurde blockiert";
/* Explanation of what is done to keep personally identifiable information private. There is a heading that precedes this explanation which is a variable to this string. */
"%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." = "%@. Ein Konto zu erstellen benötigt keine Telefonnummer, Emailadresse oder Namen. Fang jetzt gleich ganz reibungslos an.";
@@ -33,7 +36,7 @@ Sentence composed of 2 variables to describe how many profiles a user is followi
/* Explanation of what can be done by users to earn money. There is a heading that precedes this explanation which is a variable to this string. */
"%@. Tip your friend's posts and stack sats with Bitcoin⚡, the native currency of the internet." = "%@. Belohne Beiträge deiner Freunde und sammle Sats mit Bitcoin⚡, der eigenen Währung des Internets.";
/* Number of reposts.
/* Number of tip payments on a post.
Number of profiles a user is following. */
"%lld" = "%lld";
@@ -52,9 +55,15 @@ Number of profiles a user is following. */
/* Placeholder text for About Me description. */
"Absolute Boss" = "Absoluter Macher";
/* Button to accept the end user license agreement before being allowed into the app. */
"Accept" = "Zustimmen";
/* Label to indicate the public ID of the account. */
"Account ID" = "Konto ID";
/* Title for confirmation dialog to either share, report, or block a profile. */
"Actions" = "Aktionen";
/* Button to add recommended relay server.
Button to confirm adding user inputted relay. */
"Add" = "Hinzufügen";
@@ -86,6 +95,23 @@ Number of profiles a user is following. */
/* Dropdown option label for Lightning wallet, Blixt Wallet */
"Blixt Wallet" = "Blixt Wallet";
/* Alert button to block a user.
Button to block a profile.
Context menu option for blocking users. */
"Block" = "Blockieren";
/* Alert message prompt to ask if a user should be blocked. */
"Block %@?" = "%@ blockieren?";
/* Title of alert for blocking a user. */
"Block User" = "Benutzer blockieren";
/* Sidebar menu label for Profile view. */
"Blocked" = "Blockiert";
/* Navigation title of view to see list of blocked users. */
"Blocked Users" = "Blockierte Benutzer";
/* Dropdown option label for Lightning wallet, Blue Wallet. */
"Blue Wallet" = "Blue Wallet";
@@ -95,7 +121,9 @@ Number of profiles a user is following. */
/* Context menu option for broadcasting the user's note to all of the user's connected relay servers. */
"Broadcast" = "Senden";
/* Button to cancel out of posting a note.
/* Alert button to cancel out of alert for blocking a user.
Button to cancel out of alert that creates a new mutelist.
Button to cancel out of posting a note.
Button to cancel out of reposting a post.
Button to cancel out of view adding user inputted relay.
Cancel out of logging out the user. */
@@ -141,11 +169,17 @@ Number of profiles a user is following. */
/* Context menu option for copying the JSON text from the note. */
"Copy Note JSON" = "Notiz JSON kopieren";
/* Button to copy report ID. */
"Copy Report ID" = "Meldungs-ID kopieren";
/* Context menu option for copying the text from an note. */
"Copy Text" = "Text kopieren";
/* Context menu option for copying the ID of the user who created the note. */
"Copy User ID" = "Benutzer ID kopieren";
"Copy User Pubkey" = "Öffentlichen Schlüssel des Benutzers kopieren";
/* Alert message to indicate that the blocked user could not be found. */
"Could not find user to block..." = "Der zu blockierende Benutzer konnte nicht gefunden werden...";
/* Button to create account. */
"Create" = "Erstellen";
@@ -153,6 +187,9 @@ Number of profiles a user is following. */
/* Button to create an account. */
"Create Account" = "Konto erstellen";
/* Title of alert prompting the user to create a new mutelist. */
"Create new mutelist" = "Neue Stummschaltungsliste";
/* Example description about Bitcoin creator(s), Satoshi Nakamoto. */
"Creator(s) of Bitcoin. Absolute legend." = "Erfinder von Bitcoin. Absolute Legende(n).";
@@ -162,7 +199,8 @@ Number of profiles a user is following. */
/* Button to pay a Lightning invoice with the user's default Lightning wallet. */
"Default Wallet" = "Voreingestelltes Wallet";
/* Button to delete a relay server that the user connects to. */
/* Button to delete a relay server that the user connects to.
Button to remove a user from their blocklist. */
"Delete" = "Löschen";
/* Button to dismiss a text field alert. */
@@ -199,6 +237,9 @@ Number of profiles a user is following. */
/* Error message indicating why saving keys failed. */
"Error: %@" = "Fehler: %@";
/* Label indicating that the below text is the EULA, an acronym for End User License Agreement. */
"EULA" = "Endbenutzer-Lizenzvereinbarung";
/* Filter state for seeing either only posts, or posts & replies. */
"Filter State" = "Filter Einstellung";
@@ -206,11 +247,11 @@ Number of profiles a user is following. */
"Follow" = "Folgen";
/* Label describing followers of a user. */
"Followers" = "Follower";
"Followers" = "Gefolgte:r";
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of following a profile.
Part of a larger sentence to describe how many profiles a user is following. */
"Following" = "Folgt";
"Following" = "Gefolgt";
/* Label to indicate that the user is in the process of following another user. */
"Following..." = "Folge…";
@@ -219,7 +260,7 @@ Part of a larger sentence to describe how many profiles a user is following. */
"Follows" = "Folgt";
/* Navigation bar title for Global view where posts from all connected relay servers appear. */
"Global" = "Weltweit";
"Global" = "Allgemein";
/* Navigation link to go to post referenced by hex code. */
"Goto post %@" = "Gehe zum Beitrag %@";
@@ -236,9 +277,15 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Placeholder example text for website URL for user profile. */
"https://jb55.com" = "https://jb55.com";
/* Button for user to report that the account or content has illegal content. */
"Illegal content" = "Illegaler Inhalt";
/* Error message indicating that an invalid account key was entered for login. */
"Invalid key" = "Ungültiger Schlüssel";
/* Button for user to report that the account or content has spam. */
"It's spam" = "Es ist Spam";
/* Placeholder example text for identifier used for NIP-05 verification. */
"jb55@jb55.com" = "jb55@jb55.com";
@@ -278,6 +325,9 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Label for NIP-05 Verification section of user profile form. */
"NIP-05 Verification" = "NIP-05-Verifizierung";
/* Alert message prompt that asks if the user wants to create a new block list, overwriting previous block lists. */
"No block list found, create a new one? This will overwrite any previous block lists." = "Es wurde keine Blockier-Liste gefunden, soll eine neue erzeugt werden? Dies wird eine frühere Blockier-Liste überschreiben.";
/* No search results. */
"none" = "keine";
@@ -293,6 +343,9 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Prompt for user to enter in an account key to login. This text shows the characters the key could start with if it was a private key. */
"nsec1..." = "nsec1...";
/* Button for user to report that the account or content has nudity or explicit content. */
"Nudity or explicit content" = "Nacktheit oder anstößige Inhalte";
/* Label indicating that a form input is optional. */
"optional" = "optional";
@@ -344,12 +397,18 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Section title for recommend relay servers that could be added as part of configuration */
"Recommended Relays" = "Empfohlene Relays";
/* Button to reject the end user license agreement, which disallows the user from being let into the app. */
"Reject" = "Ablehnen";
/* Text field for relay server. Used for testing purposes. */
"Relay" = "Relay";
/* Sidebar menu label for Relay servers view */
"Relays" = "Relays";
/* Description of what was done as a result of sending a report to relay servers. */
"Relays have been notified and clients will be able to use this information to filter content. Thank you!" = "Relays wurden benachrichtigt und Anwendungen können diese Information nutzen, um Inhalte zu filtern. Vielen Dank!";
/* Button label to remove all participants from a note reply. */
"Remove all" = "Alle entfernen";
@@ -362,6 +421,16 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Indicating that the user is replying to the following listed people. */
"Replying to:" = "Antwort an:";
/* Button to report a profile.
Context menu option for reporting content. */
"Report" = "Melden";
/* Label indicating that the text underneath is the identifier of the report that was sent to relay servers. */
"Report ID:" = "Meldungs-ID";
/* Message indicating that a report was successfully sent to relay servers. */
"Report sent!" = "Meldung versandt!";
/* Button to confirm reposting a post.
Title of alert for confirming to repost a post. */
"Repost" = "Selbst teilen";
@@ -369,6 +438,9 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Text indicating that the post was reposted (i.e. re-shared). */
"Reposted" = "Selbst geteilt";
/* Navigation bar title for Reposts view. */
"Reposts" = "Geteilte Beiträge";
/* Picker option for DM selector for seeing only message requests (DMs that someone else sent the user which has not been responded to yet). DM is the English abbreviation for Direct Message. */
"Requests" = "Anfragen";
@@ -415,7 +487,8 @@ Part of a larger sentence to describe how many profiles a user is following. */
Sidebar menu label for accessing the app settings */
"Settings" = "Einstellungen";
/* Button to share an image. */
/* Button to share an image.
Button to share the link to a profile. */
"Share" = "Teilen";
/* Toggle to show or hide user's secret account login key. */
@@ -430,6 +503,12 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Dropdown option label for Lightning wallet, Strike. */
"Strike" = "Strike";
/* Button to close out of alert that informs that the action to block a user was successful. */
"Thanks!" = "Danke!";
/* Button for user to report that the account is impersonating someone. */
"They are impersonating someone" = "Sie gibt sich für jemand anderen aus";
/* Warning that the inputted account key is a public key and the result of what happens because of it. */
"This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective." = "Dies ist ein öffentlicher Schlüssel, mit dem Sie keine Beiträge verfassen oder in irgendeiner Weise interagieren können. Er wird verwendet, um Konten aus deren Perspektive zu betrachten.";
@@ -464,6 +543,12 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Text to indicate that the button next to it is in a state that will unfollow a profile when tapped. */
"Unfollows" = "Entfolgen";
/* Alert message to indicate */
"User blocked" = "Benutzer blockiert";
/* Alert message that informs a user was blocked. */
"User has been blocked" = "Der Benutzer wurde blockiert";
/* Label for Username section of user profile form.
Label to prompt username entry. */
"Username" = "Benutzername";
@@ -486,15 +571,24 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Text to welcome user. */
"Welcome, %@!" = "Willkommen, %@!";
/* Header text to prompt user what issue they want to report. */
"What do you want to report?" = "Was möchtest du melden?";
/* Placeholder example for relay server address. */
"wss://some.relay.com" = "wss://ein.relay.at";
/* Text of button that confirms to overwrite the existing mutelist. */
"Yes, Overwrite" = "Ja, überschreiben";
/* You, in this context, is the person who controls their own social network. You is used in the context of a larger sentence that welcomes the reader to the social network that they control themself. */
"you" = "Du";
/* Label for Your Name section of user profile form. */
"Your Name" = "Dein Name";
/* Footer text to inform user what will happen when the report is submitted. */
"Your report will be sent to the relays you are connected to" = "Die Meldung wird an Relays versendet, mit denen du verbunden bist";
/* Dropdown option label for Lightning wallet, Zebedee. */
"Zebedee" = "Zebedee";

View File

@@ -27,9 +27,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>Follower</string>
<string>Gefolgte:r</string>
<key>other</key>
<string>Follower</string>
<string>Gefolgte</string>
</dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>

View File

@@ -8,7 +8,7 @@
"'%@' is an invalid nip05 identifier. It should look like an email." = "'%@' ist eine ungültige nip05 Kennzeichnung. Diese sollte wie eine Emailadresse aussehen. ";
/* Navigation bar title for view that shows who is following a user. */
"(Profile.displayName(profile: profile, pubkey: whos))'s Followers" = "(Profile.displayName(profile: profile, pubkey: whos)) Follower";
"(Profile.displayName(profile: profile, pubkey: whos))'s Followers" = "(Profile.displayName(profile: profile, pubkey: whos)) Gefolgte";
/* Navigation bar title for view that shows who a user is following. */
"(who) following" = "(who) folgt";
@@ -20,20 +20,23 @@
Abbreviated version of a nostr public key. */
"%@" = "%@";
/* Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.
/* Sentence composed of 2 variables to describe how many tip payments there are on a post. In source English, the first variable is the number of tip payments, and the second variable is 'Tip' or 'Tips'.
Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'. */
"%@ %@" = "%@ %@";
/* Alert message that informs a user was blocked. */
"%@ has been blocked" = "%@ wurde blockiert";
/* Explanation of what is done to keep personally identifiable information private. There is a heading that precedes this explanation which is a variable to this string. */
"%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." = "Für das Erstellen eines Accounts ist keine Telefonnumer, E-Mail-Adresse und kein Name notwendig. Lege direkt los!";
"%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." = "%@. Ein Konto zu erstellen benötigt keine Telefonnummer, Emailadresse oder Namen. Fang jetzt gleich ganz reibungslos an.";
/* Explanation of what is done to keep private data encrypted. There is a heading that precedes this explanation which is a variable to this string. */
"%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs" = "%@. Ende-zu-Ende verschlüsselte private Nachrichten. Halte „Big Tech“ aus deinen Direktnachrichten heraus.";
"%@. End-to-End encrypted private messaging. Keep Big Tech out of your DMs" = "%@. End-zu-End verschlüsselter privater Nachrichtenaustausch. Halte Tech-Riesen aus deinen PNs heraus";
/* Explanation of what can be done by users to earn money. There is a heading that precedes this explanation which is a variable to this string. */
"%@. Tip your friend's posts and stack sats with Bitcoin⚡, the native currency of the internet." = "%@. Belohne Beiträge deiner Freunde und sammle Sats mit Bitcoin⚡, der eigenen Währung des Internets.";
/* Number of reposts.
/* Number of tip payments on a post.
Number of profiles a user is following. */
"%lld" = "%lld";
@@ -52,9 +55,15 @@ Number of profiles a user is following. */
/* Placeholder text for About Me description. */
"Absolute Boss" = "Absoluter Macher";
/* Button to accept the end user license agreement before being allowed into the app. */
"Accept" = "Zustimmen";
/* Label to indicate the public ID of the account. */
"Account ID" = "Konto-ID";
/* Title for confirmation dialog to either share, report, or block a profile. */
"Actions" = "Aktionen";
/* Button to add recommended relay server.
Button to confirm adding user inputted relay. */
"Add" = "Hinzufügen";
@@ -72,7 +81,7 @@ Number of profiles a user is following. */
"Are you sure you want to repost this?" = "Bist du sicher dass Du den Beitrag auf deinem Profil teilen möchtest?";
/* Label for Banner Image section of user profile form. */
"Banner Image" = "Banner Bild";
"Banner Image" = "Bannerbild";
/* Reminder to user that they should save their account information. */
"Before we get started, you'll need to save your account info, otherwise you won't be able to login in the future if you ever uninstall Damus." = "Bevor wir anfangen, musst du deine Kontodaten sichern, sonst kannst du dich in Zukunft nicht mehr anmelden, wenn du Damus jemals deinstallierst.";
@@ -86,6 +95,23 @@ Number of profiles a user is following. */
/* Dropdown option label for Lightning wallet, Blixt Wallet */
"Blixt Wallet" = "Blixt Wallet";
/* Alert button to block a user.
Button to block a profile.
Context menu option for blocking users. */
"Block" = "Blockieren";
/* Alert message prompt to ask if a user should be blocked. */
"Block %@?" = "%@ blockieren?";
/* Title of alert for blocking a user. */
"Block User" = "Benutzer blockieren";
/* Sidebar menu label for Profile view. */
"Blocked" = "Blockiert";
/* Navigation title of view to see list of blocked users. */
"Blocked Users" = "Blockierte Benutzer";
/* Dropdown option label for Lightning wallet, Blue Wallet. */
"Blue Wallet" = "Blue Wallet";
@@ -95,7 +121,9 @@ Number of profiles a user is following. */
/* Context menu option for broadcasting the user's note to all of the user's connected relay servers. */
"Broadcast" = "Senden";
/* Button to cancel out of posting a note.
/* Alert button to cancel out of alert for blocking a user.
Button to cancel out of alert that creates a new mutelist.
Button to cancel out of posting a note.
Button to cancel out of reposting a post.
Button to cancel out of view adding user inputted relay.
Cancel out of logging out the user. */
@@ -105,7 +133,7 @@ Number of profiles a user is following. */
"Cash App" = "Cash App";
/* Navigation bar title for Chatroom view. */
"Chat" = "Unterhaltung";
"Chat" = "Unterhaltungen";
/* Button for clearing cached data. */
"Clear" = "Löschen";
@@ -130,7 +158,7 @@ Number of profiles a user is following. */
"Copy Image URL" = "Bild-URL kopieren";
/* Title of section for copying a Lightning invoice identifier. */
"Copy invoice" = "Rechnung kopieren";
"Copy invoice" = "Zahlungsdaten kopieren";
/* Context menu option for copying a user's Lightning URL. */
"Copy LNURL" = "LNURL kopieren";
@@ -141,11 +169,17 @@ Number of profiles a user is following. */
/* Context menu option for copying the JSON text from the note. */
"Copy Note JSON" = "Notiz-JSON kopieren";
/* Button to copy report ID. */
"Copy Report ID" = "Meldungs-ID kopieren";
/* Context menu option for copying the text from an note. */
"Copy Text" = "Text kopieren";
/* Context menu option for copying the ID of the user who created the note. */
"Copy User ID" = "Benutzer-ID kopieren";
"Copy User Pubkey" = "Öffentlichen Schlüssel des Benutzers kopieren";
/* Alert message to indicate that the blocked user could not be found. */
"Could not find user to block..." = "Der zu blockierende Benutzer konnte nicht gefunden werden...";
/* Button to create account. */
"Create" = "Erstellen";
@@ -153,6 +187,9 @@ Number of profiles a user is following. */
/* Button to create an account. */
"Create Account" = "Konto erstellen";
/* Title of alert prompting the user to create a new mutelist. */
"Create new mutelist" = "Neue Stummschaltungsliste";
/* Example description about Bitcoin creator(s), Satoshi Nakamoto. */
"Creator(s) of Bitcoin. Absolute legend." = "Erfinder von Bitcoin. Absolute Legende(n).";
@@ -162,7 +199,8 @@ Number of profiles a user is following. */
/* Button to pay a Lightning invoice with the user's default Lightning wallet. */
"Default Wallet" = "Voreingestellte Wallet";
/* Button to delete a relay server that the user connects to. */
/* Button to delete a relay server that the user connects to.
Button to remove a user from their blocklist. */
"Delete" = "Löschen";
/* Button to dismiss a text field alert. */
@@ -172,7 +210,7 @@ Number of profiles a user is following. */
"Display Name" = "Profilname";
/* DM selector for seeing either DMs or message requests, which are messages that have not been responded to yet. DM is the English abbreviation for Direct Message. */
"DM Type" = "PN Art";
"DM Type" = "PN Typ";
/* Navigation title for DMs view, where DM is the English abbreviation for Direct Message.
Navigation title for view of DMs, where DM is an English abbreviation for Direct Message. */
@@ -199,6 +237,9 @@ Number of profiles a user is following. */
/* Error message indicating why saving keys failed. */
"Error: %@" = "Fehler: %@";
/* Label indicating that the below text is the EULA, an acronym for End User License Agreement. */
"EULA" = "Endbenutzer-Lizenzvereinbarung";
/* Filter state for seeing either only posts, or posts & replies. */
"Filter State" = "Filter Einstellung";
@@ -206,11 +247,11 @@ Number of profiles a user is following. */
"Follow" = "Folgen";
/* Label describing followers of a user. */
"Followers" = "Follower";
"Followers" = "Gefolgte:r";
/* Text to indicate that the button next to it is in a state that indicates that it is in the process of following a profile.
Part of a larger sentence to describe how many profiles a user is following. */
"Following" = "Folgt";
"Following" = "Gefolgt";
/* Label to indicate that the user is in the process of following another user. */
"Following..." = "Folge…";
@@ -219,7 +260,7 @@ Part of a larger sentence to describe how many profiles a user is following. */
"Follows" = "Folgt";
/* Navigation bar title for Global view where posts from all connected relay servers appear. */
"Global" = "Weltweit";
"Global" = "Allgemein";
/* Navigation link to go to post referenced by hex code. */
"Goto post %@" = "Gehe zum Beitrag %@";
@@ -231,14 +272,20 @@ Part of a larger sentence to describe how many profiles a user is following. */
"Home" = "Heim";
/* Placeholder example text for profile picture URL. */
"https://example.com/pic.jpg" = "https://beispiel.de/bild.jpg";
"https://example.com/pic.jpg" = "https://beispiel.at/bild.jpg";
/* Placeholder example text for website URL for user profile. */
"https://jb55.com" = "https://jb55.com";
/* Button for user to report that the account or content has illegal content. */
"Illegal content" = "Illegaler Inhalt";
/* Error message indicating that an invalid account key was entered for login. */
"Invalid key" = "Ungültiger Schlüssel";
/* Button for user to report that the account or content has spam. */
"It's spam" = "Es ist Spam";
/* Placeholder example text for identifier used for NIP-05 verification. */
"jb55@jb55.com" = "jb55@jb55.com";
@@ -278,6 +325,9 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Label for NIP-05 Verification section of user profile form. */
"NIP-05 Verification" = "NIP-05-Verifizierung";
/* Alert message prompt that asks if the user wants to create a new block list, overwriting previous block lists. */
"No block list found, create a new one? This will overwrite any previous block lists." = "Es wurde keine Blockier-Liste gefunden, soll eine neue erzeugt werden? Dies wird eine frühere Blockier-Liste überschreiben.";
/* No search results. */
"none" = "keine";
@@ -293,6 +343,9 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Prompt for user to enter in an account key to login. This text shows the characters the key could start with if it was a private key. */
"nsec1..." = "nsec1...";
/* Button for user to report that the account or content has nudity or explicit content. */
"Nudity or explicit content" = "Nacktheit oder anstößige Inhalte";
/* Label indicating that a form input is optional. */
"optional" = "optional";
@@ -344,12 +397,18 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Section title for recommend relay servers that could be added as part of configuration */
"Recommended Relays" = "Empfohlene Relays";
/* Button to reject the end user license agreement, which disallows the user from being let into the app. */
"Reject" = "Ablehnen";
/* Text field for relay server. Used for testing purposes. */
"Relay" = "Relay";
/* Sidebar menu label for Relay servers view */
"Relays" = "Relays";
/* Description of what was done as a result of sending a report to relay servers. */
"Relays have been notified and clients will be able to use this information to filter content. Thank you!" = "Relays wurden benachrichtigt und Anwendungen können diese Information nutzen, um Inhalte zu filtern. Vielen Dank!";
/* Button label to remove all participants from a note reply. */
"Remove all" = "Alle entfernen";
@@ -362,12 +421,25 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Indicating that the user is replying to the following listed people. */
"Replying to:" = "Du antwortest:";
/* Button to report a profile.
Context menu option for reporting content. */
"Report" = "Melden";
/* Label indicating that the text underneath is the identifier of the report that was sent to relay servers. */
"Report ID:" = "Meldungs-ID";
/* Message indicating that a report was successfully sent to relay servers. */
"Report sent!" = "Meldung versandt!";
/* Button to confirm reposting a post.
Title of alert for confirming to repost a post. */
"Repost" = "Teilen";
"Repost" = "Selbst teilen";
/* Text indicating that the post was reposted (i.e. re-shared). */
"Reposted" = "Geteilt";
"Reposted" = "Selbst geteilt";
/* Navigation bar title for Reposts view. */
"Reposts" = "Geteilte Beiträge";
/* Picker option for DM selector for seeing only message requests (DMs that someone else sent the user which has not been responded to yet). DM is the English abbreviation for Direct Message. */
"Requests" = "Anfragen";
@@ -376,7 +448,7 @@ Part of a larger sentence to describe how many profiles a user is following. */
"Reset" = "Zurücksetzen";
/* Button to retry completing account creation after an error occurred. */
"Retry" = "Wiederholung";
"Retry" = "Erneut versuchen";
/* Dropdown option label for Lightning wallet, River */
"River" = "River";
@@ -391,7 +463,7 @@ Part of a larger sentence to describe how many profiles a user is following. */
"Save" = "Speichern";
/* Context menu option to save an image. */
"Save Image" = "Bild speichern";
"Save Image" = "Bild sichern";
/* Navigation link to search hashtag. */
"Search hashtag: #%@" = "Hashtag suchen: #%@";
@@ -403,7 +475,7 @@ Part of a larger sentence to describe how many profiles a user is following. */
"Secret Account Login Key" = "Geheimer Konto-Anmeldeschlüssel";
/* Title of section for selecting a Lightning wallet to pay a Lightning invoice. */
"Select a Lightning wallet" = "Wähle eine Lightning-Wallet";
"Select a Lightning wallet" = "Wähle ein Lightning Wallet";
/* Prompt selection of user's default wallet */
"Select default wallet" = "Wähle ein voreingestelltes Wallet";
@@ -415,7 +487,8 @@ Part of a larger sentence to describe how many profiles a user is following. */
Sidebar menu label for accessing the app settings */
"Settings" = "Einstellungen";
/* Button to share an image. */
/* Button to share an image.
Button to share the link to a profile. */
"Share" = "Teilen";
/* Toggle to show or hide user's secret account login key. */
@@ -430,6 +503,12 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Dropdown option label for Lightning wallet, Strike. */
"Strike" = "Strike";
/* Button to close out of alert that informs that the action to block a user was successful. */
"Thanks!" = "Danke!";
/* Button for user to report that the account is impersonating someone. */
"They are impersonating someone" = "Sie gibt sich für jemand anderen aus";
/* Warning that the inputted account key is a public key and the result of what happens because of it. */
"This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective." = "Dies ist ein öffentlicher Schlüssel, Du wirst keine Beiträge teilen oder oder auf irgendeine Weise interagieren können. Dies wird genutzt um Kontos aus deren Perspektive zu sehen.";
@@ -464,6 +543,12 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Text to indicate that the button next to it is in a state that will unfollow a profile when tapped. */
"Unfollows" = "Entfolgen";
/* Alert message to indicate */
"User blocked" = "Benutzer blockiert";
/* Alert message that informs a user was blocked. */
"User has been blocked" = "Der Benutzer wurde blockiert";
/* Label for Username section of user profile form.
Label to prompt username entry. */
"Username" = "Benutzername";
@@ -486,8 +571,14 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Text to welcome user. */
"Welcome, %@!" = "Willkommen, %@!";
/* Header text to prompt user what issue they want to report. */
"What do you want to report?" = "Was möchtest du melden?";
/* Placeholder example for relay server address. */
"wss://some.relay.com" = "wss://irgendein.relay.de";
"wss://some.relay.com" = "wss://ein.relay.at";
/* Text of button that confirms to overwrite the existing mutelist. */
"Yes, Overwrite" = "Ja, überschreiben";
/* You, in this context, is the person who controls their own social network. You is used in the context of a larger sentence that welcomes the reader to the social network that they control themself. */
"you" = "Du";
@@ -495,6 +586,9 @@ Part of a larger sentence to describe how many profiles a user is following. */
/* Label for Your Name section of user profile form. */
"Your Name" = "Dein Name";
/* Footer text to inform user what will happen when the report is submitted. */
"Your report will be sent to the relays you are connected to" = "Die Meldung wird an Relays versendet, mit denen du verbunden bist";
/* Dropdown option label for Lightning wallet, Zebedee. */
"Zebedee" = "Zebedee";

View File

@@ -27,9 +27,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>Follower</string>
<string>Gefolgte:r</string>
<key>other</key>
<string>Follower</string>
<string>Gefolgte</string>
</dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@FOLLOWERS@</string>
@@ -77,9 +77,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>&amp; %d andere</string>
<string> &amp; %d andere</string>
<key>other</key>
<string>&amp; %d andere</string>
<string> &amp; %d andere</string>
<key>zero</key>
<string></string>
</dict>
@@ -95,9 +95,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>&amp; %d andere</string>
<string> &amp; %d andere</string>
<key>other</key>
<string>&amp; %d andere</string>
<string> &amp; %d andere</string>
<key>zero</key>
<string></string>
</dict>
@@ -113,9 +113,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>Mal geteilt</string>
<string>geteilter Beitrag</string>
<key>other</key>
<string>Mal geteilt</string>
<string>geteilte Beiträge</string>
</dict>
</dict>
<key>sats_count</key>

View File

@@ -0,0 +1,3 @@
#!/bin/zsh
xcodebuild -exportLocalizations -project damus.xcodeproj -localizationPath "translations" -exportLanguage en-US

8
devtools/import-translation.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/zsh
if [ -z "$*" ]; then
echo "Usage: ./devtools/import-translation.sh <locale_code_in_snake_case>"
return
fi
find "translations" -name "${1}.xliff" | grep -v "en-US.xliff" | xargs -I % xcodebuild -importLocalizations -project damus.xcodeproj -localizationPath %

View File

@@ -3,8 +3,8 @@ git:
- filter_type: file
file_format: XLIFF
source_language: en_US
source_file: damus Localizations/en-US.xcloc/Localized Contents/en-US.xliff
translation_files_expression: damus Localizations/<lang>.xcloc/Localized Contents/<lang>.xliff
source_file: translations/en-US.xcloc/Localized Contents/en-US.xliff
translation_files_expression: translations/<lang>.xliff
settings:
pr_branch_name: transifex/<br_unique_id>

View File

@@ -45,9 +45,15 @@ Abbreviated version of a nostr public key.</note>
<source>%@ %@</source>
<target>%@ %@</target>
<note>Sentence composed of 2 variables to describe how many reposts. In source English, the first variable is the number of reposts, and the second variable is 'Repost' or 'Reposts'.
<note>Sentence composed of 2 variables to describe how many tip payments there are on a post. In source English, the first variable is the number of tip payments, and the second variable is 'Tip' or 'Tips'.
Sentence composed of 2 variables to describe how many profiles a user is following. In source English, the first variable is the number of profiles being followed, and the second variable is 'Following'.</note>
</trans-unit>
<trans-unit id="%@ has been blocked" xml:space="preserve">
<source>%@ has been blocked</source>
<target>%@ wurde blockiert</target>
<note>Alert message that informs a user was blocked.</note>
</trans-unit>
<trans-unit id="%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction." xml:space="preserve">
<source>%@. Creating an account doesn't require a phone number, email or name. Get started right away with zero friction.</source>
<target>%@. Ein Konto zu erstellen benötigt keine Telefonnummer, Emailadresse oder Namen. Fang jetzt gleich ganz reibungslos an.</target>
@@ -70,7 +76,7 @@ Sentence composed of 2 variables to describe how many profiles a user is followi
<source>%lld</source>
<target>%lld</target>
<note>Number of reposts.
<note>Number of tip payments on a post.
Number of profiles a user is following.</note>
</trans-unit>
<trans-unit id="%lld/%lld" xml:space="preserve">
@@ -93,7 +99,7 @@ Number of profiles a user is following.</note>
</trans-unit>
<trans-unit id="(Profile.displayName(profile: profile, pubkey: whos))'s Followers" xml:space="preserve">
<source>(Profile.displayName(profile: profile, pubkey: whos))'s Followers</source>
<target>(Profile.displayName(profile: profile, pubkey: whos)) Follower</target>
<target>(Profile.displayName(profile: profile, pubkey: whos)) Gefolgte</target>
<note>Navigation bar title for view that shows who is following a user.</note>
</trans-unit>
@@ -133,12 +139,24 @@ Number of profiles a user is following.</note>
<note>Placeholder text for About Me description.</note>
</trans-unit>
<trans-unit id="Accept" xml:space="preserve">
<source>Accept</source>
<target>Zustimmen</target>
<note>Button to accept the end user license agreement before being allowed into the app.</note>
</trans-unit>
<trans-unit id="Account ID" xml:space="preserve">
<source>Account ID</source>
<target>Konto ID</target>
<note>Label to indicate the public ID of the account.</note>
</trans-unit>
<trans-unit id="Actions" xml:space="preserve">
<source>Actions</source>
<target>Aktionen</target>
<note>Title for confirmation dialog to either share, report, or block a profile.</note>
</trans-unit>
<trans-unit id="Add" xml:space="preserve">
<source>Add</source>
<target>Hinzufügen</target>
@@ -200,6 +218,38 @@ Number of profiles a user is following.</note>
<note>Dropdown option label for Lightning wallet, Blixt Wallet</note>
</trans-unit>
<trans-unit id="Block" xml:space="preserve">
<source>Block</source>
<target>Blockieren</target>
<note>Alert button to block a user.
Button to block a profile.
Context menu option for blocking users.</note>
</trans-unit>
<trans-unit id="Block %@?" xml:space="preserve">
<source>Block %@?</source>
<target>%@ blockieren?</target>
<note>Alert message prompt to ask if a user should be blocked.</note>
</trans-unit>
<trans-unit id="Block User" xml:space="preserve">
<source>Block User</source>
<target>Benutzer blockieren</target>
<note>Title of alert for blocking a user.</note>
</trans-unit>
<trans-unit id="Blocked" xml:space="preserve">
<source>Blocked</source>
<target>Blockiert</target>
<note>Sidebar menu label for Profile view.</note>
</trans-unit>
<trans-unit id="Blocked Users" xml:space="preserve">
<source>Blocked Users</source>
<target>Blockierte Benutzer</target>
<note>Navigation title of view to see list of blocked users.</note>
</trans-unit>
<trans-unit id="Blue Wallet" xml:space="preserve">
<source>Blue Wallet</source>
<target>Blue Wallet</target>
@@ -222,7 +272,9 @@ Number of profiles a user is following.</note>
<source>Cancel</source>
<target>Abbrechen</target>
<note>Button to cancel out of posting a note.
<note>Alert button to cancel out of alert for blocking a user.
Button to cancel out of alert that creates a new mutelist.
Button to cancel out of posting a note.
Button to cancel out of reposting a post.
Button to cancel out of view adding user inputted relay.
Cancel out of logging out the user.</note>
@@ -300,15 +352,21 @@ Number of profiles a user is following.</note>
<note>Context menu option for copying the JSON text from the note.</note>
</trans-unit>
<trans-unit id="Copy Report ID" xml:space="preserve">
<source>Copy Report ID</source>
<target>Meldungs-ID kopieren</target>
<note>Button to copy report ID.</note>
</trans-unit>
<trans-unit id="Copy Text" xml:space="preserve">
<source>Copy Text</source>
<target>Text kopieren</target>
<note>Context menu option for copying the text from an note.</note>
</trans-unit>
<trans-unit id="Copy User ID" xml:space="preserve">
<source>Copy User ID</source>
<target>Benutzer ID kopieren</target>
<trans-unit id="Copy User Pubkey" xml:space="preserve">
<source>Copy User Pubkey</source>
<target>Öffentlichen Schlüssel des Benutzers kopieren</target>
<note>Context menu option for copying the ID of the user who created the note.</note>
</trans-unit>
@@ -318,6 +376,12 @@ Number of profiles a user is following.</note>
<note>Title of section for copying a Lightning invoice identifier.</note>
</trans-unit>
<trans-unit id="Could not find user to block..." xml:space="preserve">
<source>Could not find user to block...</source>
<target>Der zu blockierende Benutzer konnte nicht gefunden werden...</target>
<note>Alert message to indicate that the blocked user could not be found.</note>
</trans-unit>
<trans-unit id="Create" xml:space="preserve">
<source>Create</source>
<target>Erstellen</target>
@@ -330,6 +394,12 @@ Number of profiles a user is following.</note>
<note>Button to create an account.</note>
</trans-unit>
<trans-unit id="Create new mutelist" xml:space="preserve">
<source>Create new mutelist</source>
<target>Neue Stummschaltungsliste</target>
<note>Title of alert prompting the user to create a new mutelist.</note>
</trans-unit>
<trans-unit id="Creator(s) of Bitcoin. Absolute legend." xml:space="preserve">
<source>Creator(s) of Bitcoin. Absolute legend.</source>
<target>Erfinder von Bitcoin. Absolute Legende(n).</target>
@@ -365,7 +435,8 @@ Number of profiles a user is following.</note>
<source>Delete</source>
<target>Löschen</target>
<note>Button to delete a relay server that the user connects to.</note>
<note>Button to delete a relay server that the user connects to.
Button to remove a user from their blocklist.</note>
</trans-unit>
<trans-unit id="Dismiss" xml:space="preserve">
<source>Dismiss</source>
@@ -385,6 +456,12 @@ Number of profiles a user is following.</note>
<note>Button to dismiss wallet selection view for paying Lightning invoice.</note>
</trans-unit>
<trans-unit id="EULA" xml:space="preserve">
<source>EULA</source>
<target>Endbenutzer-Lizenzvereinbarung</target>
<note>Label indicating that the below text is the EULA, an acronym for End User License Agreement.</note>
</trans-unit>
<trans-unit id="Earn Money" xml:space="preserve">
<source>Earn Money</source>
<target>Verdiene Geld</target>
@@ -435,13 +512,13 @@ Number of profiles a user is following.</note>
</trans-unit>
<trans-unit id="Followers" xml:space="preserve">
<source>Followers</source>
<target>Follower</target>
<target>Gefolgte:r</target>
<note>Label describing followers of a user.</note>
</trans-unit>
<trans-unit id="Following" xml:space="preserve">
<source>Following</source>
<target>Folgt</target>
<target>Gefolgt</target>
<note>Text to indicate that the button next to it is in a state that indicates that it is in the process of following a profile.
Part of a larger sentence to describe how many profiles a user is following.</note>
@@ -460,7 +537,7 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="Global" xml:space="preserve">
<source>Global</source>
<target>Weltweit</target>
<target>Allgemein</target>
<note>Navigation bar title for Global view where posts from all connected relay servers appear.</note>
</trans-unit>
@@ -482,12 +559,24 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Navigation bar title for Home view where posts and replies appear from those who the user is following.</note>
</trans-unit>
<trans-unit id="Illegal content" xml:space="preserve">
<source>Illegal content</source>
<target>Illegaler Inhalt</target>
<note>Button for user to report that the account or content has illegal content.</note>
</trans-unit>
<trans-unit id="Invalid key" xml:space="preserve">
<source>Invalid key</source>
<target>Ungültiger Schlüssel</target>
<note>Error message indicating that an invalid account key was entered for login.</note>
</trans-unit>
<trans-unit id="It's spam" xml:space="preserve">
<source>It's spam</source>
<target>Es ist Spam</target>
<note>Button for user to report that the account or content has spam.</note>
</trans-unit>
<trans-unit id="LNLink" xml:space="preserve">
<source>LNLink</source>
<target>LNLink</target>
@@ -557,6 +646,12 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Label for NIP-05 Verification section of user profile form.</note>
</trans-unit>
<trans-unit id="No block list found, create a new one? This will overwrite any previous block lists." xml:space="preserve">
<source>No block list found, create a new one? This will overwrite any previous block lists.</source>
<target>Es wurde keine Blockier-Liste gefunden, soll eine neue erzeugt werden? Dies wird eine frühere Blockier-Liste überschreiben.</target>
<note>Alert message prompt that asks if the user wants to create a new block list, overwriting previous block lists.</note>
</trans-unit>
<trans-unit id="Nothing to see here. Check back later!" xml:space="preserve">
<source>Nothing to see here. Check back later!</source>
<target>Hier gibt es nichts zu sehen. Komm später wieder vorbei!</target>
@@ -569,6 +664,12 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Navigation title for notifications.</note>
</trans-unit>
<trans-unit id="Nudity or explicit content" xml:space="preserve">
<source>Nudity or explicit content</source>
<target>Nacktheit oder anstößige Inhalte</target>
<note>Button for user to report that the account or content has nudity or explicit content.</note>
</trans-unit>
<trans-unit id="Pay" xml:space="preserve">
<source>Pay</source>
<target>Bezahlen</target>
@@ -665,6 +766,12 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Section title for recommend relay servers that could be added as part of configuration</note>
</trans-unit>
<trans-unit id="Reject" xml:space="preserve">
<source>Reject</source>
<target>Ablehnen</target>
<note>Button to reject the end user license agreement, which disallows the user from being let into the app.</note>
</trans-unit>
<trans-unit id="Relay" xml:space="preserve">
<source>Relay</source>
<target>Relay</target>
@@ -677,6 +784,12 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Sidebar menu label for Relay servers view</note>
</trans-unit>
<trans-unit id="Relays have been notified and clients will be able to use this information to filter content. Thank you!" xml:space="preserve">
<source>Relays have been notified and clients will be able to use this information to filter content. Thank you!</source>
<target>Relays wurden benachrichtigt und Anwendungen können diese Information nutzen, um Inhalte zu filtern. Vielen Dank!</target>
<note>Description of what was done as a result of sending a report to relay servers.</note>
</trans-unit>
<trans-unit id="Remove all" xml:space="preserve">
<source>Remove all</source>
<target>Alle entfernen</target>
@@ -701,6 +814,25 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Indicating that the user is replying to the following listed people.</note>
</trans-unit>
<trans-unit id="Report" xml:space="preserve">
<source>Report</source>
<target>Melden</target>
<note>Button to report a profile.
Context menu option for reporting content.</note>
</trans-unit>
<trans-unit id="Report ID:" xml:space="preserve">
<source>Report ID:</source>
<target>Meldungs-ID</target>
<note>Label indicating that the text underneath is the identifier of the report that was sent to relay servers.</note>
</trans-unit>
<trans-unit id="Report sent!" xml:space="preserve">
<source>Report sent!</source>
<target>Meldung versandt!</target>
<note>Message indicating that a report was successfully sent to relay servers.</note>
</trans-unit>
<trans-unit id="Repost" xml:space="preserve">
<source>Repost</source>
<target>Selbst teilen</target>
@@ -714,6 +846,12 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Text indicating that the post was reposted (i.e. re-shared).</note>
</trans-unit>
<trans-unit id="Reposts" xml:space="preserve">
<source>Reposts</source>
<target>Geteilte Beiträge</target>
<note>Navigation bar title for Reposts view.</note>
</trans-unit>
<trans-unit id="Requests" xml:space="preserve">
<source>Requests</source>
<target>Anfragen</target>
@@ -803,7 +941,8 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<source>Share</source>
<target>Teilen</target>
<note>Button to share an image.</note>
<note>Button to share an image.
Button to share the link to a profile.</note>
</trans-unit>
<trans-unit id="Show" xml:space="preserve">
<source>Show</source>
@@ -829,6 +968,18 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Dropdown option label for Lightning wallet, Strike.</note>
</trans-unit>
<trans-unit id="Thanks!" xml:space="preserve">
<source>Thanks!</source>
<target>Danke!</target>
<note>Button to close out of alert that informs that the action to block a user was successful.</note>
</trans-unit>
<trans-unit id="They are impersonating someone" xml:space="preserve">
<source>They are impersonating someone</source>
<target>Sie gibt sich für jemand anderen aus</target>
<note>Button for user to report that the account is impersonating someone.</note>
</trans-unit>
<trans-unit id="This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective." xml:space="preserve">
<source>This is a public key, you will not be able to make posts or interact in any way. This is used for viewing accounts from their perspective.</source>
<target>Dies ist ein öffentlicher Schlüssel, mit dem Sie keine Beiträge verfassen oder in irgendeiner Weise interagieren können. Er wird verwendet, um Konten aus deren Perspektive zu betrachten.</target>
@@ -890,6 +1041,18 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Text to indicate that the button next to it is in a state that will unfollow a profile when tapped.</note>
</trans-unit>
<trans-unit id="User blocked" xml:space="preserve">
<source>User blocked</source>
<target>Benutzer blockiert</target>
<note>Alert message to indicate</note>
</trans-unit>
<trans-unit id="User has been blocked" xml:space="preserve">
<source>User has been blocked</source>
<target>Der Benutzer wurde blockiert</target>
<note>Alert message that informs a user was blocked.</note>
</trans-unit>
<trans-unit id="Username" xml:space="preserve">
<source>Username</source>
<target>Benutzername</target>
@@ -933,12 +1096,30 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Text to welcome user.</note>
</trans-unit>
<trans-unit id="What do you want to report?" xml:space="preserve">
<source>What do you want to report?</source>
<target>Was möchtest du melden?</target>
<note>Header text to prompt user what issue they want to report.</note>
</trans-unit>
<trans-unit id="Yes, Overwrite" xml:space="preserve">
<source>Yes, Overwrite</source>
<target>Ja, überschreiben</target>
<note>Text of button that confirms to overwrite the existing mutelist.</note>
</trans-unit>
<trans-unit id="Your Name" xml:space="preserve">
<source>Your Name</source>
<target>Dein Name</target>
<note>Label for Your Name section of user profile form.</note>
</trans-unit>
<trans-unit id="Your report will be sent to the relays you are connected to" xml:space="preserve">
<source>Your report will be sent to the relays you are connected to</source>
<target>Die Meldung wird an Relays versendet, mit denen du verbunden bist</target>
<note>Footer text to inform user what will happen when the report is submitted.</note>
</trans-unit>
<trans-unit id="Zebedee" xml:space="preserve">
<source>Zebedee</source>
<target>Zebedee</target>
@@ -1098,13 +1279,13 @@ Part of a larger sentence to describe how many profiles a user is following.</no
</trans-unit>
<trans-unit id="/followers_count:dict/FOLLOWERS:dict/one:dict/:string" xml:space="preserve">
<source>Follower</source>
<target>Follower</target>
<target>Gefolgte:r</target>
<note>Part of a larger sentence to describe how many people are following a user.</note>
</trans-unit>
<trans-unit id="/followers_count:dict/FOLLOWERS:dict/other:dict/:string" xml:space="preserve">
<source>Followers</source>
<target>Follower</target>
<target>Gefolgte</target>
<note>Part of a larger sentence to describe how many people are following a user.</note>
</trans-unit>

View File

@@ -105,6 +105,11 @@ Number of profiles a user is following.</note>
<target>@</target>
<note>Prefix character to username.</note>
</trans-unit>
<trans-unit id="API Key (optional)" xml:space="preserve">
<source>API Key (optional)</source>
<target>API Key (optional)</target>
<note>Example URL to LibreTranslate server</note>
</trans-unit>
<trans-unit id="About" xml:space="preserve">
<source>About</source>
<target>About</target>
@@ -344,6 +349,11 @@ Number of profiles a user is following.</note>
<target>Creator(s) of Bitcoin. Absolute legend.</target>
<note>Example description about Bitcoin creator(s), Satoshi Nakamoto.</note>
</trans-unit>
<trans-unit id="Custom" xml:space="preserve">
<source>Custom</source>
<target>Custom</target>
<note>Dropdown option for selecting a custom translation server.</note>
</trans-unit>
<trans-unit id="DM Type" xml:space="preserve">
<source>DM Type</source>
<target>DM Type</target>
@@ -467,6 +477,16 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>Goto profile %@</target>
<note>Navigation link to go to profile.</note>
</trans-unit>
<trans-unit id="Hide" xml:space="preserve">
<source>Hide</source>
<target>Hide</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Hide API Key" xml:space="preserve">
<source>Hide API Key</source>
<target>Hide API Key</target>
<note>Button to hide the LibreTranslate server API key.</note>
</trans-unit>
<trans-unit id="Home" xml:space="preserve">
<source>Home</source>
<target>Home</target>
@@ -502,6 +522,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>Let's go!</target>
<note>Button to complete account creation and start using the app.</note>
</trans-unit>
<trans-unit id="LibreTranslate Translations" xml:space="preserve">
<source>LibreTranslate Translations</source>
<target>LibreTranslate Translations</target>
<note>Section title for selecting the server that hosts the LibreTranslate machine translation API.</note>
</trans-unit>
<trans-unit id="Lightning Address or LNURL" xml:space="preserve">
<source>Lightning Address or LNURL</source>
<target>Lightning Address or LNURL</target>
@@ -550,6 +575,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>No block list found, create a new one? This will overwrite any previous block lists.</target>
<note>Alert message prompt that asks if the user wants to create a new block list, overwriting previous block lists.</note>
</trans-unit>
<trans-unit id="None" xml:space="preserve">
<source>None</source>
<target>None</target>
<note>Dropdown option for selecting no translation server.</note>
</trans-unit>
<trans-unit id="Nothing to see here. Check back later!" xml:space="preserve">
<source>Nothing to see here. Check back later!</source>
<target>Nothing to see here. Check back later!</target>
@@ -585,6 +615,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>Post</target>
<note>Button to post a note.</note>
</trans-unit>
<trans-unit id="Post from a user you've blocked" xml:space="preserve">
<source>Post from a user you've blocked</source>
<target>Post from a user you've blocked</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Posts" xml:space="preserve">
<source>Posts</source>
<target>Posts</target>
@@ -782,6 +817,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>Send a message to start the conversation...</target>
<note>Text prompt for user to send a message to the other user.</note>
</trans-unit>
<trans-unit id="Server" xml:space="preserve">
<source>Server</source>
<target>Server</target>
<note>Prompt selection of LibreTranslate server to perform machine translations on notes</note>
</trans-unit>
<trans-unit id="Settings" xml:space="preserve">
<source>Settings</source>
<target>Settings</target>
@@ -799,6 +839,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>Show</target>
<note>Toggle to show or hide user's secret account login key.</note>
</trans-unit>
<trans-unit id="Show API Key" xml:space="preserve">
<source>Show API Key</source>
<target>Show API Key</target>
<note>Button to hide the LibreTranslate server API key.</note>
</trans-unit>
<trans-unit id="Show wallet selector" xml:space="preserve">
<source>Show wallet selector</source>
<target>Show wallet selector</target>
@@ -850,11 +895,26 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<note>Navigation bar title for note thread.
Navigation bar title for threaded event detail view.</note>
</trans-unit>
<trans-unit id="Translate Note" xml:space="preserve">
<source>Translate Note</source>
<target>Translate Note</target>
<note>Button to translate note from different language.</note>
</trans-unit>
<trans-unit id="Translated from (languageName!)" xml:space="preserve">
<source>Translated from (languageName!)</source>
<target>Translated from (languageName!)</target>
<note>Button to indicate that the note has been translated from a different language.</note>
</trans-unit>
<trans-unit id="Type your post here..." xml:space="preserve">
<source>Type your post here...</source>
<target>Type your post here...</target>
<note>Text box prompt to ask user to type their post.</note>
</trans-unit>
<trans-unit id="URL" xml:space="preserve">
<source>URL</source>
<target>URL</target>
<note>Example URL to LibreTranslate server</note>
</trans-unit>
<trans-unit id="Unfollow" xml:space="preserve">
<source>Unfollow</source>
<target>Unfollow</target>