Merge pull request #303 from mastodon/release/1.2.0

Release v1.2.0
This commit is contained in:
CMK 2021-12-06 12:37:34 +08:00 committed by GitHub
commit feb748676f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
310 changed files with 12835 additions and 2633 deletions

View File

@ -19,8 +19,8 @@ jobs:
steps:
- name: checkout
uses: actions/checkout@v2
- name: force Xcode 12.5.1
run: sudo xcode-select -switch /Applications/Xcode_12.5.1.app
- name: force Xcode 13.1
run: sudo xcode-select -switch /Applications/Xcode_13.1.app
- name: setup
run: exec ./.github/scripts/setup.sh
- name: build

4
.gitignore vendored
View File

@ -58,6 +58,7 @@ Packages/
.swiftpm
.build/
!**/swiftpm/Package.resolved
# CocoaPods
# We recommend against adding the Pods directory to your .gitignore. However
@ -121,5 +122,4 @@ xcuserdata
Localization/StringsConvertor/input
Localization/StringsConvertor/output
.DS_Store
/Mastodon.xcworkspace/xcshareddata/swiftpm
.DS_Store

View File

@ -15,8 +15,8 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0.8</string>
<string>1.2.0</string>
<key>CFBundleVersion</key>
<string>60</string>
<string>88</string>
</dict>
</plist>

View File

@ -0,0 +1,40 @@
//
// UserDefaults+Notification.swift
// AppShared
//
// Created by Cirno MainasuK on 2021-10-9.
//
import UIKit
import CryptoKit
extension UserDefaults {
// always use hash value (SHA256) from accessToken as key
private static func deriveKey(from accessToken: String, prefix: String) -> String {
let digest = SHA256.hash(data: Data(accessToken.utf8))
let bytes = [UInt8](digest)
let hex = bytes.toHexString()
let key = prefix + "@" + hex
return key
}
private static let notificationCountKeyPrefix = "notification_count"
public func getNotificationCountWithAccessToken(accessToken: String) -> Int {
let prefix = UserDefaults.notificationCountKeyPrefix
let key = UserDefaults.deriveKey(from: accessToken, prefix: prefix)
return integer(forKey: key)
}
public func setNotificationCountWithAccessToken(accessToken: String, value: Int) {
let prefix = UserDefaults.notificationCountKeyPrefix
let key = UserDefaults.deriveKey(from: accessToken, prefix: prefix)
setValue(value, forKey: key)
}
public func increaseNotificationCount(accessToken: String) {
let count = getNotificationCountWithAccessToken(accessToken: accessToken)
setNotificationCountWithAccessToken(accessToken: accessToken, value: count + 1)
}
}

View File

@ -10,3 +10,4 @@ import UIKit
extension UserDefaults {
public static let shared = UserDefaults(suiteName: AppName.groupID)!
}

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>CoreData 2.xcdatamodel</string>
</dict>
</plist>

View File

@ -0,0 +1,306 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="19206" systemVersion="20G165" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Application" representedClassName=".Application" syncable="YES">
<attribute name="identifier" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>
<attribute name="name" attributeType="String"/>
<attribute name="vapidKey" optional="YES" attributeType="String"/>
<attribute name="website" optional="YES" attributeType="String"/>
<relationship name="status" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="application" inverseEntity="Status"/>
</entity>
<entity name="Attachment" representedClassName=".Attachment" syncable="YES">
<attribute name="blurhash" optional="YES" attributeType="String"/>
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="descriptionString" optional="YES" attributeType="String"/>
<attribute name="domain" attributeType="String"/>
<attribute name="id" attributeType="String"/>
<attribute name="index" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="metaData" optional="YES" attributeType="Binary"/>
<attribute name="previewRemoteURL" optional="YES" attributeType="String"/>
<attribute name="previewURL" optional="YES" attributeType="String"/>
<attribute name="remoteURL" optional="YES" attributeType="String"/>
<attribute name="textURL" optional="YES" attributeType="String"/>
<attribute name="typeRaw" attributeType="String"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="url" optional="YES" attributeType="String"/>
<relationship name="status" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="mediaAttachments" inverseEntity="Status"/>
</entity>
<entity name="DomainBlock" representedClassName=".DomainBlock" syncable="YES">
<attribute name="blockedDomain" attributeType="String"/>
<attribute name="createAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="domain" attributeType="String"/>
<attribute name="userID" attributeType="String"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="userID"/>
<constraint value="domain"/>
<constraint value="blockedDomain"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="Emoji" representedClassName=".Emoji" syncable="YES">
<attribute name="category" optional="YES" attributeType="String"/>
<attribute name="createAt" attributeType="Date" defaultDateTimeInterval="631123200" usesScalarValueType="NO"/>
<attribute name="identifier" attributeType="UUID" usesScalarValueType="NO"/>
<attribute name="shortcode" attributeType="String"/>
<attribute name="staticURL" attributeType="String"/>
<attribute name="url" attributeType="String"/>
<attribute name="visibleInPicker" attributeType="Boolean" usesScalarValueType="YES"/>
</entity>
<entity name="History" representedClassName=".History" syncable="YES">
<attribute name="accounts" optional="YES" attributeType="String"/>
<attribute name="createAt" attributeType="Date" defaultDateTimeInterval="631123200" usesScalarValueType="NO"/>
<attribute name="day" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="identifier" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>
<attribute name="uses" optional="YES" attributeType="String"/>
<relationship name="tag" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Tag" inverseName="histories" inverseEntity="Tag"/>
</entity>
<entity name="HomeTimelineIndex" representedClassName=".HomeTimelineIndex" syncable="YES">
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="deletedAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="domain" attributeType="String"/>
<attribute name="hasMore" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="identifier" attributeType="String"/>
<attribute name="userID" attributeType="String"/>
<relationship name="status" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="homeTimelineIndexes" inverseEntity="Status"/>
</entity>
<entity name="Instance" representedClassName=".Instance" syncable="YES">
<attribute name="configurationRaw" optional="YES" attributeType="Binary"/>
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="domain" attributeType="String"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="authentications" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonAuthentication" inverseName="instance" inverseEntity="MastodonAuthentication"/>
</entity>
<entity name="MastodonAuthentication" representedClassName=".MastodonAuthentication" syncable="YES">
<attribute name="activedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="appAccessToken" attributeType="String"/>
<attribute name="clientID" attributeType="String"/>
<attribute name="clientSecret" attributeType="String"/>
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="domain" attributeType="String"/>
<attribute name="identifier" attributeType="UUID" usesScalarValueType="NO"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="userAccessToken" attributeType="String"/>
<attribute name="userID" attributeType="String"/>
<attribute name="username" attributeType="String"/>
<relationship name="instance" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Instance" inverseName="authentications" inverseEntity="Instance"/>
<relationship name="user" maxCount="1" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="mastodonAuthentication" inverseEntity="MastodonUser"/>
</entity>
<entity name="MastodonNotification" representedClassName=".MastodonNotification" syncable="YES">
<attribute name="createAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="domain" attributeType="String"/>
<attribute name="id" attributeType="String"/>
<attribute name="identifier" attributeType="UUID" usesScalarValueType="NO"/>
<attribute name="typeRaw" attributeType="String"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="userID" attributeType="String"/>
<relationship name="account" maxCount="1" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="notifications" inverseEntity="MastodonUser"/>
<relationship name="status" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="inNotifications" inverseEntity="Status"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="id"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="MastodonUser" representedClassName=".MastodonUser" syncable="YES">
<attribute name="acct" attributeType="String"/>
<attribute name="avatar" attributeType="String"/>
<attribute name="avatarStatic" optional="YES" attributeType="String"/>
<attribute name="bot" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="displayName" attributeType="String"/>
<attribute name="domain" attributeType="String"/>
<attribute name="emojisData" optional="YES" attributeType="Binary"/>
<attribute name="fieldsData" optional="YES" attributeType="Binary"/>
<attribute name="followersCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="followingCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="header" attributeType="String"/>
<attribute name="headerStatic" optional="YES" attributeType="String"/>
<attribute name="id" attributeType="String"/>
<attribute name="identifier" attributeType="String"/>
<attribute name="locked" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="note" optional="YES" attributeType="String"/>
<attribute name="statusesCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="suspended" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="url" optional="YES" attributeType="String"/>
<attribute name="username" attributeType="String"/>
<relationship name="blocking" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="blockingBy" inverseEntity="MastodonUser"/>
<relationship name="blockingBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="blocking" inverseEntity="MastodonUser"/>
<relationship name="bookmarked" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Status" inverseName="bookmarkedBy" inverseEntity="Status"/>
<relationship name="domainBlocking" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="domainBlockingBy" inverseEntity="MastodonUser"/>
<relationship name="domainBlockingBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="domainBlocking" inverseEntity="MastodonUser"/>
<relationship name="endorsed" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="endorsedBy" inverseEntity="MastodonUser"/>
<relationship name="endorsedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="endorsed" inverseEntity="MastodonUser"/>
<relationship name="favourite" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Status" inverseName="favouritedBy" inverseEntity="Status"/>
<relationship name="following" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="followingBy" inverseEntity="MastodonUser"/>
<relationship name="followingBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="following" inverseEntity="MastodonUser"/>
<relationship name="followRequested" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="followRequestedBy" inverseEntity="MastodonUser"/>
<relationship name="followRequestedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="followRequested" inverseEntity="MastodonUser"/>
<relationship name="mastodonAuthentication" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MastodonAuthentication" inverseName="user" inverseEntity="MastodonAuthentication"/>
<relationship name="muted" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Status" inverseName="mutedBy" inverseEntity="Status"/>
<relationship name="muting" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="mutingBy" inverseEntity="MastodonUser"/>
<relationship name="mutingBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="muting" inverseEntity="MastodonUser"/>
<relationship name="notifications" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonNotification" inverseName="account" inverseEntity="MastodonNotification"/>
<relationship name="pinnedStatus" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="pinnedBy" inverseEntity="Status"/>
<relationship name="privateNotes" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="PrivateNote" inverseName="to" inverseEntity="PrivateNote"/>
<relationship name="privateNotesTo" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="PrivateNote" inverseName="from" inverseEntity="PrivateNote"/>
<relationship name="reblogged" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Status" inverseName="rebloggedBy" inverseEntity="Status"/>
<relationship name="searchHistories" toMany="YES" deletionRule="Nullify" destinationEntity="SearchHistory" inverseName="account" inverseEntity="SearchHistory"/>
<relationship name="statuses" toMany="YES" deletionRule="Nullify" destinationEntity="Status" inverseName="author" inverseEntity="Status"/>
<relationship name="votePollOptions" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="PollOption" inverseName="votedBy" inverseEntity="PollOption"/>
<relationship name="votePolls" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Poll" inverseName="votedBy" inverseEntity="Poll"/>
</entity>
<entity name="Mention" representedClassName=".Mention" syncable="YES">
<attribute name="acct" attributeType="String"/>
<attribute name="createAt" attributeType="Date" defaultDateTimeInterval="631123200" usesScalarValueType="NO"/>
<attribute name="id" attributeType="String"/>
<attribute name="identifier" attributeType="UUID" usesScalarValueType="NO"/>
<attribute name="index" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="url" attributeType="String"/>
<attribute name="username" attributeType="String"/>
<relationship name="status" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="mentions" inverseEntity="Status"/>
</entity>
<entity name="Poll" representedClassName=".Poll" syncable="YES">
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="expired" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="expiresAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="id" attributeType="String"/>
<attribute name="multiple" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="votersCount" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="votesCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="options" toMany="YES" deletionRule="Cascade" destinationEntity="PollOption" inverseName="poll" inverseEntity="PollOption"/>
<relationship name="status" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="poll" inverseEntity="Status"/>
<relationship name="votedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="votePolls" inverseEntity="MastodonUser"/>
</entity>
<entity name="PollOption" representedClassName=".PollOption" syncable="YES">
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="index" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="title" attributeType="String"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="votesCount" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="poll" maxCount="1" deletionRule="Nullify" destinationEntity="Poll" inverseName="options" inverseEntity="Poll"/>
<relationship name="votedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="votePollOptions" inverseEntity="MastodonUser"/>
</entity>
<entity name="PrivateNote" representedClassName=".PrivateNote" syncable="YES">
<attribute name="note" optional="YES" attributeType="String"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="from" maxCount="1" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="privateNotesTo" inverseEntity="MastodonUser"/>
<relationship name="to" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="privateNotes" inverseEntity="MastodonUser"/>
</entity>
<entity name="SearchHistory" representedClassName=".SearchHistory" syncable="YES">
<attribute name="createAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="domain" attributeType="String" defaultValueString=""/>
<attribute name="identifier" attributeType="UUID" usesScalarValueType="NO"/>
<attribute name="updatedAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="userID" attributeType="String" defaultValueString=""/>
<relationship name="account" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="searchHistories" inverseEntity="MastodonUser"/>
<relationship name="hashtag" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Tag" inverseName="searchHistories" inverseEntity="Tag"/>
<relationship name="status" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="searchHistories" inverseEntity="Status"/>
</entity>
<entity name="Setting" representedClassName=".Setting" syncable="YES">
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="domain" attributeType="String"/>
<attribute name="preferredStaticAvatar" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="preferredStaticEmoji" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="preferredTrueBlackDarkMode" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="preferredUsingDefaultBrowser" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="userID" attributeType="String"/>
<relationship name="subscriptions" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Subscription" inverseName="setting" inverseEntity="Subscription"/>
</entity>
<entity name="Status" representedClassName=".Status" syncable="YES">
<attribute name="content" attributeType="String"/>
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="deletedAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="domain" attributeType="String"/>
<attribute name="emojisData" optional="YES" attributeType="Binary"/>
<attribute name="favouritesCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="id" attributeType="String"/>
<attribute name="identifier" attributeType="String"/>
<attribute name="inReplyToAccountID" optional="YES" attributeType="String"/>
<attribute name="inReplyToID" optional="YES" attributeType="String"/>
<attribute name="language" optional="YES" attributeType="String"/>
<attribute name="reblogsCount" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="repliesCount" optional="YES" attributeType="Integer 64" usesScalarValueType="NO"/>
<attribute name="revealedAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="sensitive" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="spoilerText" optional="YES" attributeType="String"/>
<attribute name="text" optional="YES" attributeType="String"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="uri" attributeType="String"/>
<attribute name="url" attributeType="String"/>
<attribute name="visibility" optional="YES" attributeType="String"/>
<relationship name="application" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Application" inverseName="status" inverseEntity="Application"/>
<relationship name="author" maxCount="1" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="statuses" inverseEntity="MastodonUser"/>
<relationship name="bookmarkedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="bookmarked" inverseEntity="MastodonUser"/>
<relationship name="favouritedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="favourite" inverseEntity="MastodonUser"/>
<relationship name="homeTimelineIndexes" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="HomeTimelineIndex" inverseName="status" inverseEntity="HomeTimelineIndex"/>
<relationship name="inNotifications" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MastodonNotification" inverseName="status" inverseEntity="MastodonNotification"/>
<relationship name="mediaAttachments" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Attachment" inverseName="status" inverseEntity="Attachment"/>
<relationship name="mentions" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="Mention" inverseName="status" inverseEntity="Mention"/>
<relationship name="mutedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="muted" inverseEntity="MastodonUser"/>
<relationship name="pinnedBy" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="pinnedStatus" inverseEntity="MastodonUser"/>
<relationship name="poll" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="Poll" inverseName="status" inverseEntity="Poll"/>
<relationship name="reblog" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="reblogFrom" inverseEntity="Status"/>
<relationship name="reblogFrom" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="Status" inverseName="reblog" inverseEntity="Status"/>
<relationship name="rebloggedBy" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonUser" inverseName="reblogged" inverseEntity="MastodonUser"/>
<relationship name="replyFrom" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Status" inverseName="replyTo" inverseEntity="Status"/>
<relationship name="replyTo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Status" inverseName="replyFrom" inverseEntity="Status"/>
<relationship name="searchHistories" toMany="YES" deletionRule="Nullify" destinationEntity="SearchHistory" inverseName="status" inverseEntity="SearchHistory"/>
</entity>
<entity name="Subscription" representedClassName=".Subscription" syncable="YES">
<attribute name="activedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="endpoint" optional="YES" attributeType="String"/>
<attribute name="id" optional="YES" attributeType="String"/>
<attribute name="policyRaw" attributeType="String"/>
<attribute name="serverKey" optional="YES" attributeType="String"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="userToken" optional="YES" attributeType="String"/>
<relationship name="alert" maxCount="1" deletionRule="Cascade" destinationEntity="SubscriptionAlerts" inverseName="subscription" inverseEntity="SubscriptionAlerts"/>
<relationship name="setting" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Setting" inverseName="subscriptions" inverseEntity="Setting"/>
</entity>
<entity name="SubscriptionAlerts" representedClassName=".SubscriptionAlerts" syncable="YES">
<attribute name="createdAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="favouriteRaw" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="followRaw" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="followRequestRaw" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="mentionRaw" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="pollRaw" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="reblogRaw" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="updatedAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="subscription" maxCount="1" deletionRule="Nullify" destinationEntity="Subscription" inverseName="alert" inverseEntity="Subscription"/>
</entity>
<entity name="Tag" representedClassName=".Tag" syncable="YES">
<attribute name="createAt" attributeType="Date" defaultDateTimeInterval="631123200" usesScalarValueType="NO"/>
<attribute name="identifier" attributeType="UUID" usesScalarValueType="NO"/>
<attribute name="name" attributeType="String"/>
<attribute name="updatedAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="url" attributeType="String"/>
<relationship name="histories" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="History" inverseName="tag" inverseEntity="History"/>
<relationship name="searchHistories" toMany="YES" deletionRule="Nullify" destinationEntity="SearchHistory" inverseName="hashtag" inverseEntity="SearchHistory"/>
</entity>
<elements>
<element name="Application" positionX="0" positionY="0" width="128" height="104"/>
<element name="Attachment" positionX="0" positionY="0" width="128" height="254"/>
<element name="DomainBlock" positionX="45" positionY="162" width="128" height="89"/>
<element name="Emoji" positionX="0" positionY="0" width="128" height="134"/>
<element name="History" positionX="0" positionY="0" width="128" height="119"/>
<element name="HomeTimelineIndex" positionX="0" positionY="0" width="128" height="134"/>
<element name="MastodonAuthentication" positionX="0" positionY="0" width="128" height="224"/>
<element name="MastodonNotification" positionX="9" positionY="162" width="128" height="164"/>
<element name="MastodonUser" positionX="0" positionY="0" width="128" height="734"/>
<element name="Mention" positionX="0" positionY="0" width="128" height="149"/>
<element name="Poll" positionX="0" positionY="0" width="128" height="194"/>
<element name="PollOption" positionX="0" positionY="0" width="128" height="134"/>
<element name="PrivateNote" positionX="0" positionY="0" width="128" height="89"/>
<element name="SearchHistory" positionX="0" positionY="0" width="128" height="149"/>
<element name="Setting" positionX="72" positionY="162" width="128" height="164"/>
<element name="Status" positionX="0" positionY="0" width="128" height="599"/>
<element name="Subscription" positionX="81" positionY="171" width="128" height="179"/>
<element name="SubscriptionAlerts" positionX="72" positionY="162" width="128" height="14"/>
<element name="Tag" positionX="0" positionY="0" width="128" height="134"/>
<element name="Instance" positionX="45" positionY="162" width="128" height="104"/>
</elements>
</model>

View File

@ -13,6 +13,8 @@ import AppShared
public final class CoreDataStack {
static let logger = Logger(subsystem: "CoreDataStack", category: "DB")
private(set) var storeDescriptions: [NSPersistentStoreDescription]
public let didFinishLoad = CurrentValueSubject<Bool, Never>(false)
@ -90,8 +92,22 @@ public final class CoreDataStack {
container.viewContext.automaticallyMergesChangesFromParent = true
os_log("%{public}s[%{public}ld], %{public}s: %s", ((#file as NSString).lastPathComponent), #line, #function, storeDescription.debugDescription)
callback()
#if DEBUG
do {
let storeURL = URL.storeURL(for: AppName.groupID, databaseName: "shared")
let data = try Data(contentsOf: storeURL)
let formatter = ByteCountFormatter()
formatter.allowedUnits = [.useMB]
formatter.countStyle = .file
let size = formatter.string(fromByteCount: Int64(data.count))
CoreDataStack.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): Database size: \(size)")
} catch {
CoreDataStack.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): Cannot get database size")
}
#endif
})
}

View File

@ -0,0 +1,70 @@
//
// Instance.swift
// CoreDataStack
//
// Created by Cirno MainasuK on 2021-10-9.
//
import Foundation
import CoreData
public final class Instance: NSManagedObject {
@NSManaged public var domain: String
@NSManaged public private(set) var createdAt: Date
@NSManaged public private(set) var updatedAt: Date
@NSManaged public private(set) var configurationRaw: Data?
// MARK: one-to-many relationships
@NSManaged public var authentications: Set<MastodonAuthentication>
}
extension Instance {
public override func awakeFromInsert() {
super.awakeFromInsert()
let now = Date()
setPrimitiveValue(now, forKey: #keyPath(Instance.createdAt))
setPrimitiveValue(now, forKey: #keyPath(Instance.updatedAt))
}
@discardableResult
public static func insert(
into context: NSManagedObjectContext,
property: Property
) -> Instance {
let instance: Instance = context.insertObject()
instance.domain = property.domain
return instance
}
public func update(configurationRaw: Data?) {
self.configurationRaw = configurationRaw
}
public func didUpdate(at networkDate: Date) {
self.updatedAt = networkDate
}
}
extension Instance {
public struct Property {
public let domain: String
public init(domain: String) {
self.domain = domain
}
}
}
extension Instance: Managed {
public static var defaultSortDescriptors: [NSSortDescriptor] {
return [NSSortDescriptor(keyPath: \Instance.createdAt, ascending: false)]
}
}
extension Instance {
public static func predicate(domain: String) -> NSPredicate {
return NSPredicate(format: "%K == %@", #keyPath(Instance.domain), domain)
}
}

View File

@ -30,6 +30,9 @@ final public class MastodonAuthentication: NSManagedObject {
// one-to-one relationship
@NSManaged public private(set) var user: MastodonUser
// many-to-one relationship
@NSManaged public private(set) var instance: Instance?
}
extension MastodonAuthentication {
@ -97,6 +100,12 @@ extension MastodonAuthentication {
}
}
public func update(instance: Instance) {
if self.instance != instance {
self.instance = instance
}
}
public func didUpdate(at networkDate: Date) {
self.updatedAt = networkDate
}
@ -143,7 +152,7 @@ extension MastodonAuthentication: Managed {
extension MastodonAuthentication {
static func predicate(domain: String) -> NSPredicate {
public static func predicate(domain: String) -> NSPredicate {
return NSPredicate(format: "%K == %@", #keyPath(MastodonAuthentication.domain), domain)
}
@ -158,4 +167,8 @@ extension MastodonAuthentication {
])
}
public static func predicate(userAccessToken: String) -> NSPredicate {
return NSPredicate(format: "%K == %@", #keyPath(MastodonAuthentication.userAccessToken), userAccessToken)
}
}

View File

@ -43,11 +43,11 @@ final public class MastodonUser: NSManagedObject {
// one-to-one relationship
@NSManaged public private(set) var pinnedStatus: Status?
@NSManaged public private(set) var mastodonAuthentication: MastodonAuthentication?
@NSManaged public private(set) var searchHistory: SearchHistory?
// one-to-many relationship
@NSManaged public private(set) var statuses: Set<Status>?
@NSManaged public private(set) var notifications: Set<MastodonNotification>?
@NSManaged public private(set) var searchHistories: Set<SearchHistory>
// many-to-many relationship
@NSManaged public private(set) var favourite: Set<Status>?
@ -274,6 +274,15 @@ extension MastodonUser {
}
extension MastodonUser {
public func findSearchHistory(domain: String, userID: MastodonUser.ID) -> SearchHistory? {
return searchHistories.first { searchHistory in
return searchHistory.domain == domain
&& searchHistory.userID == userID
}
}
}
extension MastodonUser {
public struct Property {
public let identifier: String

View File

@ -16,7 +16,7 @@ public final class SearchHistory: NSManagedObject {
@NSManaged public private(set) var createAt: Date
@NSManaged public private(set) var updatedAt: Date
// one-to-one relationship
// many-to-one relationship
@NSManaged public private(set) var account: MastodonUser?
@NSManaged public private(set) var hashtag: Tag?
@NSManaged public private(set) var status: Status?
@ -31,10 +31,10 @@ extension SearchHistory {
setPrimitiveValue(Date(), forKey: #keyPath(SearchHistory.updatedAt))
}
public override func willSave() {
super.willSave()
setPrimitiveValue(Date(), forKey: #keyPath(SearchHistory.updatedAt))
}
// public override func willSave() {
// super.willSave()
// setPrimitiveValue(Date(), forKey: #keyPath(SearchHistory.updatedAt))
// }
@discardableResult
public static func insert(

View File

@ -13,7 +13,7 @@ public final class Setting: NSManagedObject {
@NSManaged public var domain: String
@NSManaged public var userID: String
@NSManaged public var appearanceRaw: String
// @NSManaged public var appearanceRaw: String
@NSManaged public var preferredTrueBlackDarkMode: Bool
@NSManaged public var preferredStaticAvatar: Bool
@NSManaged public var preferredStaticEmoji: Bool
@ -41,17 +41,17 @@ extension Setting {
property: Property
) -> Setting {
let setting: Setting = context.insertObject()
setting.appearanceRaw = property.appearanceRaw
// setting.appearanceRaw = property.appearanceRaw
setting.domain = property.domain
setting.userID = property.userID
return setting
}
public func update(appearanceRaw: String) {
guard appearanceRaw != self.appearanceRaw else { return }
self.appearanceRaw = appearanceRaw
didUpdate(at: Date())
}
// public func update(appearanceRaw: String) {
// guard appearanceRaw != self.appearanceRaw else { return }
// self.appearanceRaw = appearanceRaw
// didUpdate(at: Date())
// }
public func update(preferredTrueBlackDarkMode: Bool) {
guard preferredTrueBlackDarkMode != self.preferredTrueBlackDarkMode else { return }
@ -87,12 +87,16 @@ extension Setting {
public struct Property {
public let domain: String
public let userID: String
public let appearanceRaw: String
// public let appearanceRaw: String
public init(domain: String, userID: String, appearanceRaw: String) {
public init(
domain: String,
userID: String
// appearanceRaw: String
) {
self.domain = domain
self.userID = userID
self.appearanceRaw = appearanceRaw
// self.appearanceRaw = appearanceRaw
}
}
}

View File

@ -52,18 +52,18 @@ public final class Status: NSManagedObject {
// one-to-one relationship
@NSManaged public private(set) var pinnedBy: MastodonUser?
@NSManaged public private(set) var poll: Poll?
@NSManaged public private(set) var searchHistory: SearchHistory?
// one-to-many relationship
@NSManaged public private(set) var reblogFrom: Set<Status>?
@NSManaged public private(set) var mentions: Set<Mention>?
@NSManaged public private(set) var tags: Set<Tag>?
@NSManaged public private(set) var homeTimelineIndexes: Set<HomeTimelineIndex>?
@NSManaged public private(set) var mediaAttachments: Set<Attachment>?
@NSManaged public private(set) var replyFrom: Set<Status>?
@NSManaged public private(set) var inNotifications: Set<MastodonNotification>?
@NSManaged public private(set) var searchHistories: Set<SearchHistory>
@NSManaged public private(set) var updatedAt: Date
@NSManaged public private(set) var deletedAt: Date?
@NSManaged public private(set) var revealedAt: Date?
@ -81,7 +81,6 @@ extension Status {
replyTo: Status?,
poll: Poll?,
mentions: [Mention]?,
tags: [Tag]?,
mediaAttachments: [Attachment]?,
favouritedBy: MastodonUser?,
rebloggedBy: MastodonUser?,
@ -126,9 +125,6 @@ extension Status {
if let mentions = mentions {
status.mutableSetValue(forKey: #keyPath(Status.mentions)).addObjects(from: mentions)
}
if let tags = tags {
status.mutableSetValue(forKey: #keyPath(Status.tags)).addObjects(from: tags)
}
if let mediaAttachments = mediaAttachments {
status.mutableSetValue(forKey: #keyPath(Status.mediaAttachments)).addObjects(from: mediaAttachments)
}

View File

@ -18,13 +18,12 @@ public final class Tag: NSManagedObject {
@NSManaged public private(set) var url: String
// one-to-one relationship
@NSManaged public private(set) var searchHistory: SearchHistory?
// many-to-many relationship
@NSManaged public private(set) var statuses: Set<Status>?
// one-to-many relationship
@NSManaged public private(set) var histories: Set<History>?
@NSManaged public private(set) var searchHistories: Set<SearchHistory>
}
public extension Tag {
@ -55,6 +54,15 @@ public extension Tag {
}
}
extension Tag {
public func findSearchHistory(domain: String, userID: MastodonUser.ID) -> SearchHistory? {
return searchHistories.first { searchHistory in
return searchHistory.domain == domain
&& searchHistory.userID == userID
}
}
}
public extension Tag {
struct Property {
public let name: String

View File

@ -15,8 +15,8 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0.8</string>
<string>1.2.0</string>
<key>CFBundleVersion</key>
<string>60</string>
<string>88</string>
</dict>
</plist>

View File

@ -15,8 +15,8 @@
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0.8</string>
<string>1.2.0</string>
<key>CFBundleVersion</key>
<string>60</string>
<string>88</string>
</dict>
</plist>

View File

@ -2,6 +2,28 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>no unread notification</string>
<key>one</key>
<string>1 unread notification</string>
<key>few</key>
<string>%ld unread notifications</string>
<key>many</key>
<string>%ld unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -1,51 +1,51 @@
"16wxgf" = "Post on Mastodon";
"16wxgf" = "النَشر على ماستودون";
"751xkl" = "Text Content";
"751xkl" = "محتوى نصي";
"CsR7G2" = "Post on Mastodon";
"CsR7G2" = "انشر على ماستدون";
"HZSGTr" = "What content to post?";
"HZSGTr" = "ما المُحتوى المُراد نشره؟";
"HdGikU" = "Posting failed";
"HdGikU" = "فَشَلَ النشر";
"KDNTJ4" = "Failure Reason";
"KDNTJ4" = "سبب الإخفاق";
"RHxKOw" = "Send Post with text content";
"RHxKOw" = "إرسال مَنشور يَحوي نص";
"RxSqsb" = "Post";
"RxSqsb" = "مَنشور";
"WCIR3D" = "Post ${content} on Mastodon";
"WCIR3D" = "نَشر ${content} على ماستودون";
"ZKJSNu" = "Post";
"ZKJSNu" = "مَنشور";
"ZS1XaK" = "${content}";
"ZbSjzC" = "Visibility";
"ZbSjzC" = "مدى الظهور";
"Zo4jgJ" = "Post Visibility";
"Zo4jgJ" = "مدى ظهور المنشور";
"apSxMG-dYQ5NN" = "There are ${count} options matching Public.";
"apSxMG-dYQ5NN" = "هُناك عدد ${count} خِيار مُطابق لِـ\"عام\".";
"apSxMG-ehFLjY" = "There are ${count} options matching Followers Only.";
"apSxMG-ehFLjY" = "هُناك عدد ${count} خِيار مُطابق لِـ\"المُتابِعُون فقط\".";
"ayoYEb-dYQ5NN" = "${content}, Public";
"ayoYEb-dYQ5NN" = "${content}، عام";
"ayoYEb-ehFLjY" = "${content}, Followers Only";
"ayoYEb-ehFLjY" = "${content}، المُتابِعُون فقط";
"dUyuGg" = "Post on Mastodon";
"dUyuGg" = "النشر على ماستدون";
"dYQ5NN" = "Public";
"dYQ5NN" = "للعامة";
"ehFLjY" = "Followers Only";
"ehFLjY" = "لمتابعيك فقط";
"gfePDu" = "Posting failed. ${failureReason}";
"gfePDu" = "فَشَلَ النشر، ${failureReason}";
"k7dbKQ" = "Post was sent successfully.";
"k7dbKQ" = "تمَّ إرسال المنشور بِنجاح.";
"oGiqmY-dYQ5NN" = "Just to confirm, you wanted Public?";
"oGiqmY-dYQ5NN" = "للتأكيد، هل تَريد \"عام\"؟";
"oGiqmY-ehFLjY" = "Just to confirm, you wanted Followers Only?";
"oGiqmY-ehFLjY" = "للتأكيد، هل تُريد \"للمُتابِعين فقط\"؟";
"rM6dvp" = "URL";
"rM6dvp" = "عنوان URL";
"ryJLwG" = "Post was sent successfully. ";
"ryJLwG" = "تم إرسال المنشور بنجاح. ";

View File

@ -5,7 +5,7 @@
<key>There are ${count} options matching ${content}. - 2</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>There are %#@count_option@ matching ${content}.</string>
<string>هُناك %#@count_option@ تتطابق مَعَ '${content}'.</string>
<key>count_option</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -13,23 +13,23 @@
<key>NSStringFormatValueTypeKey</key>
<string>%ld</string>
<key>zero</key>
<string>%ld options</string>
<string>لا خيار</string>
<key>one</key>
<string>1 option</string>
<string>خيار واحد</string>
<key>two</key>
<string>%ld options</string>
<string>خياران</string>
<key>few</key>
<string>%ld options</string>
<string>%ld خيارات</string>
<key>many</key>
<string>%ld options</string>
<string>%ld خيارًا</string>
<key>other</key>
<string>%ld options</string>
<string>%ld خيار</string>
</dict>
</dict>
<key>There are ${count} options matching ${visibility}.</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>There are %#@count_option@ matching ${visibility}.</string>
<string>هُناك %#@count_option@ تتطابق مَعَ '${visibility}'.</string>
<key>count_option</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -37,17 +37,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>%ld</string>
<key>zero</key>
<string>%ld options</string>
<string>لا خيار</string>
<key>one</key>
<string>1 option</string>
<string>خيار واحد</string>
<key>two</key>
<string>%ld options</string>
<string>خياران</string>
<key>few</key>
<string>%ld options</string>
<string>%ld خيارات</string>
<key>many</key>
<string>%ld options</string>
<string>%ld خيارًا</string>
<key>other</key>
<string>%ld options</string>
<string>%ld خيار</string>
</dict>
</dict>
</dict>

View File

@ -1,28 +1,28 @@
"16wxgf" = "Post on Mastodon";
"16wxgf" = "Publier sur Mastodon";
"751xkl" = "Text Content";
"751xkl" = "Contenu textuel";
"CsR7G2" = "Post on Mastodon";
"CsR7G2" = "Publier sur Mastodon";
"HZSGTr" = "What content to post?";
"HZSGTr" = "Quel contenu à publier ?";
"HdGikU" = "Posting failed";
"HdGikU" = "Échec lors de la publication";
"KDNTJ4" = "Failure Reason";
"KDNTJ4" = "Raison de léchec";
"RHxKOw" = "Send Post with text content";
"RHxKOw" = "Envoyer une publication avec du contenu texte";
"RxSqsb" = "Post";
"WCIR3D" = "Post ${content} on Mastodon";
"WCIR3D" = "Publier du ${content} sur Mastodon";
"ZKJSNu" = "Post";
"ZKJSNu" = "Publication";
"ZS1XaK" = "${content}";
"ZbSjzC" = "Visibility";
"ZbSjzC" = "Visibilité";
"Zo4jgJ" = "Post Visibility";
"Zo4jgJ" = "Visibilité de la publication";
"apSxMG-dYQ5NN" = "There are ${count} options matching Public.";
@ -30,22 +30,22 @@
"ayoYEb-dYQ5NN" = "${content}, Public";
"ayoYEb-ehFLjY" = "${content}, Followers Only";
"ayoYEb-ehFLjY" = "${content}, abonné·e·s seulement";
"dUyuGg" = "Post on Mastodon";
"dUyuGg" = "Publier sur Mastodon";
"dYQ5NN" = "Public";
"ehFLjY" = "Followers Only";
"ehFLjY" = "Abonné·e·s seulement";
"gfePDu" = "Posting failed. ${failureReason}";
"gfePDu" = "Échec lors de la publication. ${failureReason}";
"k7dbKQ" = "Post was sent successfully.";
"k7dbKQ" = "Message publié avec succès.";
"oGiqmY-dYQ5NN" = "Just to confirm, you wanted Public?";
"oGiqmY-dYQ5NN" = "Juste pour confirmer, vous vouliez « Public » ?";
"oGiqmY-ehFLjY" = "Just to confirm, you wanted Followers Only?";
"oGiqmY-ehFLjY" = "Juste pour confirmer, vous vouliez bien diffuser vers « abonné·e·s uniquement » ?";
"rM6dvp" = "URL";
"ryJLwG" = "Post was sent successfully. ";
"ryJLwG" = "La publication a été envoyée avec succès. ";

View File

@ -5,7 +5,7 @@
<key>There are ${count} options matching ${content}. - 2</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>There are %#@count_option@ matching ${content}.</string>
<string>Il y a %#@count_option@ correspondant à « ${content} ».</string>
<key>count_option</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -21,7 +21,7 @@
<key>There are ${count} options matching ${visibility}.</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>There are %#@count_option@ matching ${visibility}.</string>
<string>Il y a %#@count_option@ correspondant à « ${visibility} ».</string>
<key>count_option</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>

View File

@ -24,9 +24,9 @@
"Zo4jgJ" = "Faicsinneachd a phuist";
"apSxMG-dYQ5NN" = "There are ${count} options matching Public.";
"apSxMG-dYQ5NN" = "Tha ${count} roghainn(ean) dha “Poblach” ann.";
"apSxMG-ehFLjY" = "There are ${count} options matching Followers Only.";
"apSxMG-ehFLjY" = "Tha ${count} roghainn(ean) dha “Luchd-leantainn a-mhàin” ann.";
"ayoYEb-dYQ5NN" = "${content}, poblach";

View File

@ -13,11 +13,11 @@
<key>NSStringFormatValueTypeKey</key>
<string>%ld</string>
<key>one</key>
<string>1 option</string>
<string>%ld roghainn</string>
<key>two</key>
<string>%ld options</string>
<string>%ld roghainn</string>
<key>few</key>
<string>%ld options</string>
<string>%ld roghainnean</string>
<key>other</key>
<string>%ld roghainn</string>
</dict>
@ -33,11 +33,11 @@
<key>NSStringFormatValueTypeKey</key>
<string>%ld</string>
<key>one</key>
<string>1 option</string>
<string>%ld roghainn</string>
<key>two</key>
<string>%ld options</string>
<string>%ld roghainn</string>
<key>few</key>
<string>%ld options</string>
<string>%ld roghainnean</string>
<key>other</key>
<string>%ld roghainn</string>
</dict>

View File

@ -0,0 +1,51 @@
"16wxgf" = "Di Mastodon de biweşîne";
"751xkl" = "Naveroka nivîsê";
"CsR7G2" = "Di Mastodon de biweşîne";
"HZSGTr" = "Kîjan naverok bila bê şandin?";
"HdGikU" = "Şandin têkçû";
"KDNTJ4" = "Sedema têkçûnê";
"RHxKOw" = "Bi naveroka nivîsî şandiyan bişîne";
"RxSqsb" = "Şandî";
"WCIR3D" = "${content} biweşîne di Mastodon de";
"ZKJSNu" = "Şandî";
"ZS1XaK" = "${content}";
"ZbSjzC" = "Xuyanî";
"Zo4jgJ" = "Xuyaniya şandiyê";
"apSxMG-dYQ5NN" = "Vebijarkên ${count} hene ku li gorî 'Gelemperî' ne.";
"apSxMG-ehFLjY" = "Vebijarkên ${count} hene ku li gorî 'Tenê Şopaneran' hene.";
"ayoYEb-dYQ5NN" = "${content}, Gelemperî";
"ayoYEb-ehFLjY" = "${content}, Tenê şopînêr";
"dUyuGg" = "Di Mastodon de biweşîne";
"dYQ5NN" = "Gelemperî";
"ehFLjY" = "Tenê şopîneran";
"gfePDu" = "Weşandin bi ser neket. ${failureReason}";
"k7dbKQ" = "Şandî bi serkeftî hate şandin.";
"oGiqmY-dYQ5NN" = "Tenê ji bo pejirandinê, te 'Gelemperî' dixwest?";
"oGiqmY-ehFLjY" = "Tenê ji bo pejirandinê, te 'Tenê Şopîner' dixwest?";
"rM6dvp" = "Girêdan";
"ryJLwG" = "Şandî bi serkeftî hate şandin. ";

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>There are ${count} options matching ${content}. - 2</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_option@ heye ku bi ${content} re têkildar e.</string>
<key>count_option</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>%ld</string>
<key>one</key>
<string>1 vebijêrk</string>
<key>other</key>
<string>%ld vebijêrk</string>
</dict>
</dict>
<key>There are ${count} options matching ${visibility}.</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_option@ heye ku bi ${visibility} re têkildar e.</string>
<key>count_option</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>%ld</string>
<key>one</key>
<string>1 vebijêrk</string>
<key>other</key>
<string>%ld vebijêrk</string>
</dict>
</dict>
</dict>
</plist>

View File

@ -5,7 +5,7 @@
<key>There are ${count} options matching ${content}. - 2</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>There are %#@count_option@ matching ${content}.</string>
<string>Er zijn %#@count_option@ die overeenkomen met ${content}.</string>
<key>count_option</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -13,7 +13,7 @@
<key>NSStringFormatValueTypeKey</key>
<string>%ld</string>
<key>one</key>
<string>1 option</string>
<string>1 optie</string>
<key>other</key>
<string>%ld options</string>
</dict>
@ -21,7 +21,7 @@
<key>There are ${count} options matching ${visibility}.</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>There are %#@count_option@ matching ${visibility}.</string>
<string>Er zijn %#@count_option@ die overeenkomen met ${visibility}.</string>
<key>count_option</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -29,7 +29,7 @@
<key>NSStringFormatValueTypeKey</key>
<string>%ld</string>
<key>one</key>
<string>1 option</string>
<string>1 optie</string>
<key>other</key>
<string>%ld options</string>
</dict>

View File

@ -51,6 +51,7 @@ private func map(language: String) -> String? {
case "fr_FR": return "fr" // French
case "de_DE": return "de" // German
case "ja_JP": return "ja" // Japanese
case "kmr_TR": return "ku-TR" // Kurmanji (Kurdish)
case "ru_RU": return "ru" // Russian
case "gd_GB": return "gd-GB" // Scottish Gaelic
case "es_ES": return "es" // Spanish

View File

@ -2,10 +2,34 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>لا إشعار غير مقروء</string>
<key>one</key>
<string>إشعار واحِد غير مقروء</string>
<key>two</key>
<string>إشعاران غير مقروءان</string>
<key>few</key>
<string>%ld إشعارات غير مقروءة</string>
<key>many</key>
<string>%ld إشعارًا غيرَ مقروء</string>
<key>other</key>
<string>%ld إشعار غير مقروء</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>Input limit exceeds %#@character_count@</string>
<string>تمَّ تجاوز حدّ الإدخال %#@character_count@</string>
<key>character_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -13,23 +37,23 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld characters</string>
<string>لا حرف</string>
<key>one</key>
<string>1 character</string>
<string>حرفٌ واحِد</string>
<key>two</key>
<string>%ld characters</string>
<string>حرفان اثنان</string>
<key>few</key>
<string>%ld characters</string>
<string>%ld حُرُوف</string>
<key>many</key>
<string>%ld characters</string>
<string>%ld حرفًا</string>
<key>other</key>
<string>%ld characters</string>
<string>%ld حَرف</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_remains</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>Input limit remains %#@character_count@</string>
<string>يتبقَّى على حدّ الإدخال %#@character_count@</string>
<key>character_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -37,17 +61,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld characters</string>
<string>لا حرف</string>
<key>one</key>
<string>1 character</string>
<string>حرفٌ واحِد</string>
<key>two</key>
<string>%ld characters</string>
<string>حرفان اثنان</string>
<key>few</key>
<string>%ld characters</string>
<string>%ld حُرُوف</string>
<key>many</key>
<string>%ld characters</string>
<string>%ld حرفًا</string>
<key>other</key>
<string>%ld characters</string>
<string>%ld حَرف</string>
</dict>
</dict>
<key>plural.count.metric_formatted.post</key>
@ -61,17 +85,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>posts</string>
<string>لا منشور</string>
<key>one</key>
<string>post</string>
<string>منشور</string>
<key>two</key>
<string>posts</string>
<string>منشوران</string>
<key>few</key>
<string>posts</string>
<string>منشورات</string>
<key>many</key>
<string>posts</string>
<string>منشورًا</string>
<key>other</key>
<string>posts</string>
<string>منشور</string>
</dict>
</dict>
<key>plural.count.post</key>
@ -85,17 +109,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld posts</string>
<string>لا منشور</string>
<key>one</key>
<string>1 post</string>
<string>منشورٌ واحِد</string>
<key>two</key>
<string>%ld posts</string>
<string>منشورانِ اثنان</string>
<key>few</key>
<string>%ld posts</string>
<string>%ld منشورات</string>
<key>many</key>
<string>%ld posts</string>
<string>%ld منشورًا</string>
<key>other</key>
<string>%ld posts</string>
<string>%ld منشور</string>
</dict>
</dict>
<key>plural.count.favorite</key>
@ -109,17 +133,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld favorites</string>
<string>لا إعجاب</string>
<key>one</key>
<string>1 favorite</string>
<string>إعجابٌ واحِد</string>
<key>two</key>
<string>%ld favorites</string>
<string>إعجابانِ اثنان</string>
<key>few</key>
<string>%ld favorites</string>
<string>%ld إعجابات</string>
<key>many</key>
<string>%ld favorites</string>
<string>%ld إعجابًا</string>
<key>other</key>
<string>%ld favorites</string>
<string>%ld إعجاب</string>
</dict>
</dict>
<key>plural.count.reblog</key>
@ -133,17 +157,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld reblogs</string>
<string>لا إعاد تدوين</string>
<key>one</key>
<string>1 reblog</string>
<string>إعادةُ تدوينٍ واحِدة</string>
<key>two</key>
<string>%ld reblogs</string>
<string>إعادتا تدوين</string>
<key>few</key>
<string>%ld reblogs</string>
<string>%ld إعاداتِ تدوين</string>
<key>many</key>
<string>%ld reblogs</string>
<string>%ld إعادةٍ للتدوين</string>
<key>other</key>
<string>%ld reblogs</string>
<string>%ld إعادة تدوين</string>
</dict>
</dict>
<key>plural.count.vote</key>
@ -157,17 +181,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld votes</string>
<string>لا صوت</string>
<key>one</key>
<string>1 vote</string>
<string>صوتٌ واحِد</string>
<key>two</key>
<string>%ld votes</string>
<string>صوتانِ اثنان</string>
<key>few</key>
<string>%ld votes</string>
<string>%ld أصوات</string>
<key>many</key>
<string>%ld votes</string>
<string>%ld صوتًا</string>
<key>other</key>
<string>%ld votes</string>
<string>%ld صوت</string>
</dict>
</dict>
<key>plural.count.voter</key>
@ -181,17 +205,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld voters</string>
<string>لا مُصوِّتون</string>
<key>one</key>
<string>1 voter</string>
<string>مُصوِّتٌ واحِد</string>
<key>two</key>
<string>%ld voters</string>
<string>مُصوِّتانِ اثنان</string>
<key>few</key>
<string>%ld voters</string>
<string>%ld مُصوِّتين</string>
<key>many</key>
<string>%ld voters</string>
<string>%ld مُصوِّتًا</string>
<key>other</key>
<string>%ld voters</string>
<string>%ld مُصوِّت</string>
</dict>
</dict>
<key>plural.people_talking</key>
@ -205,17 +229,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld people talking</string>
<string>لا أحَدَ يتحدَّث</string>
<key>one</key>
<string>1 people talking</string>
<string>شخصٌ واحدٌ يتحدَّث</string>
<key>two</key>
<string>%ld people talking</string>
<string>شخصانِ اثنان يتحدَّثا</string>
<key>few</key>
<string>%ld people talking</string>
<string>%ld أشخاصٍ يتحدَّثون</string>
<key>many</key>
<string>%ld people talking</string>
<string>%ld شخصًا يتحدَّثون</string>
<key>other</key>
<string>%ld people talking</string>
<string>%ld شخصٍ يتحدَّثون</string>
</dict>
</dict>
<key>plural.count.following</key>
@ -229,17 +253,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld following</string>
<string>لا مُتابَع</string>
<key>one</key>
<string>1 following</string>
<string>مُتابَعٌ واحد</string>
<key>two</key>
<string>%ld following</string>
<string>مُتابَعانِ</string>
<key>few</key>
<string>%ld following</string>
<string>%ld مُتابَعين</string>
<key>many</key>
<string>%ld following</string>
<string>%ld مُتابَعًا</string>
<key>other</key>
<string>%ld following</string>
<string>%ld مُتابَع</string>
</dict>
</dict>
<key>plural.count.follower</key>
@ -253,17 +277,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld followers</string>
<string>لا مُتابِع</string>
<key>one</key>
<string>1 follower</string>
<string>مُتابِعٌ واحد</string>
<key>two</key>
<string>%ld followers</string>
<string>مُتابِعانِ اثنان</string>
<key>few</key>
<string>%ld followers</string>
<string>%ld مُتابِعين</string>
<key>many</key>
<string>%ld followers</string>
<string>%ld مُتابِعًا</string>
<key>other</key>
<string>%ld followers</string>
<string>%ld مُتابِع</string>
</dict>
</dict>
<key>date.year.left</key>
@ -277,17 +301,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld years left</string>
<string>تتبقى لَحظة</string>
<key>one</key>
<string>1 year left</string>
<string>تتبقى سنة</string>
<key>two</key>
<string>%ld years left</string>
<string>تتبقى سنتين</string>
<key>few</key>
<string>%ld years left</string>
<string>تتبقى %ld سنوات</string>
<key>many</key>
<string>%ld years left</string>
<string>تتبقى %ld سنةً</string>
<key>other</key>
<string>%ld years left</string>
<string>تتبقى %ld سنة</string>
</dict>
</dict>
<key>date.month.left</key>
@ -301,17 +325,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld months left</string>
<string>تتبقى لَحظة</string>
<key>one</key>
<string>1 months left</string>
<string>يتبقى شهر</string>
<key>two</key>
<string>%ld months left</string>
<string>يتبقى شهرين</string>
<key>few</key>
<string>%ld months left</string>
<string>يتبقى %ld أشهر</string>
<key>many</key>
<string>%ld months left</string>
<string>يتبقى %ld شهرًا</string>
<key>other</key>
<string>%ld months left</string>
<string>يتبقى %ld شهر</string>
</dict>
</dict>
<key>date.day.left</key>
@ -325,17 +349,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld days left</string>
<string>تتبقى لحظة</string>
<key>one</key>
<string>1 day left</string>
<string>يتبقى يوم</string>
<key>two</key>
<string>%ld days left</string>
<string>يتبقى يومين</string>
<key>few</key>
<string>%ld days left</string>
<string>يتبقى %ld أيام</string>
<key>many</key>
<string>%ld days left</string>
<string>يتبقى %ld يومًا</string>
<key>other</key>
<string>%ld days left</string>
<string>يتبقى %ld يوم</string>
</dict>
</dict>
<key>date.hour.left</key>
@ -349,17 +373,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld hours left</string>
<string>تتبقى لَحظة</string>
<key>one</key>
<string>1 hour left</string>
<string>تتبقى ساعة</string>
<key>two</key>
<string>%ld hours left</string>
<string>تتبقى ساعتين</string>
<key>few</key>
<string>%ld hours left</string>
<string>تتبقى %ld ساعات</string>
<key>many</key>
<string>%ld hours left</string>
<string>تتبقى %ld ساعةً</string>
<key>other</key>
<string>%ld hours left</string>
<string>تتبقى %ld ساعة</string>
</dict>
</dict>
<key>date.minute.left</key>
@ -373,17 +397,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld minutes left</string>
<string>تتبقى لَحظة</string>
<key>one</key>
<string>1 minute left</string>
<string>تتبقى دقيقة</string>
<key>two</key>
<string>%ld minutes left</string>
<string>تتبقى دقيقتين</string>
<key>few</key>
<string>%ld minutes left</string>
<string>تتبقى %ld دقائق</string>
<key>many</key>
<string>%ld minutes left</string>
<string>تتبقى %ld دقيقةً</string>
<key>other</key>
<string>%ld minutes left</string>
<string>تتبقى %ld دقيقة</string>
</dict>
</dict>
<key>date.second.left</key>
@ -397,17 +421,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld seconds left</string>
<string>تتبقى لَحظة</string>
<key>one</key>
<string>1 second left</string>
<string>تتبقى ثانية</string>
<key>two</key>
<string>%ld seconds left</string>
<string>تتبقى ثانيتين</string>
<key>few</key>
<string>%ld seconds left</string>
<string>تتبقى %ld ثوان</string>
<key>many</key>
<string>%ld seconds left</string>
<string>تتبقى %ld ثانيةً</string>
<key>other</key>
<string>%ld seconds left</string>
<string>تتبقى %ld ثانية</string>
</dict>
</dict>
<key>date.year.ago.abbr</key>
@ -421,17 +445,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ldy ago</string>
<string>مُنذُ لَحظة</string>
<key>one</key>
<string>1y ago</string>
<string>مُنذُ سنة</string>
<key>two</key>
<string>%ldy ago</string>
<string>مُنذُ سنتين</string>
<key>few</key>
<string>%ldy ago</string>
<string>مُنذُ %ld سنين</string>
<key>many</key>
<string>%ldy ago</string>
<string>مُنذُ %ld سنةً</string>
<key>other</key>
<string>%ldy ago</string>
<string>مُنذُ %ld سنة</string>
</dict>
</dict>
<key>date.month.ago.abbr</key>
@ -445,17 +469,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ldM ago</string>
<string>مُنذُ لَحظة</string>
<key>one</key>
<string>1M ago</string>
<string>مُنذُ شهر</string>
<key>two</key>
<string>%ldM ago</string>
<string>مُنذُ شهرين</string>
<key>few</key>
<string>%ldM ago</string>
<string>مُنذُ %ld أشهُر</string>
<key>many</key>
<string>%ldM ago</string>
<string>مُنذُ %ld شهرًا</string>
<key>other</key>
<string>%ldM ago</string>
<string>مُنذُ %ld شهر</string>
</dict>
</dict>
<key>date.day.ago.abbr</key>
@ -469,17 +493,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ldd ago</string>
<string>مُنذُ لَحظة</string>
<key>one</key>
<string>1d ago</string>
<string>مُنذُ يوم</string>
<key>two</key>
<string>%ldd ago</string>
<string>مُنذُ يومين</string>
<key>few</key>
<string>%ldd ago</string>
<string>مُنذُ %ld أيام</string>
<key>many</key>
<string>%ldd ago</string>
<string>مُنذُ %ld يومًا</string>
<key>other</key>
<string>%ldd ago</string>
<string>مُنذُ %ld يوم</string>
</dict>
</dict>
<key>date.hour.ago.abbr</key>
@ -493,17 +517,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ldh ago</string>
<string>مُنذُ لَحظة</string>
<key>one</key>
<string>1h ago</string>
<string>مُنذُ ساعة</string>
<key>two</key>
<string>%ldh ago</string>
<string>مُنذُ ساعتين</string>
<key>few</key>
<string>%ldh ago</string>
<string>مُنذُ %ld ساعات</string>
<key>many</key>
<string>%ldh ago</string>
<string>مُنذُ %ld ساعةًَ</string>
<key>other</key>
<string>%ldh ago</string>
<string>مُنذُ %ld ساعة</string>
</dict>
</dict>
<key>date.minute.ago.abbr</key>
@ -517,17 +541,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ldm ago</string>
<string>مُنذُ لَحظة</string>
<key>one</key>
<string>1m ago</string>
<string>مُنذُ دقيقة</string>
<key>two</key>
<string>%ldm ago</string>
<string>مُنذُ دقيقتان</string>
<key>few</key>
<string>%ldm ago</string>
<string>مُنذُ %ld دقائق</string>
<key>many</key>
<string>%ldm ago</string>
<string>مُنذُ %ld دقيقةً</string>
<key>other</key>
<string>%ldm ago</string>
<string>مُنذُ %ld دقيقة</string>
</dict>
</dict>
<key>date.second.ago.abbr</key>
@ -541,17 +565,17 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%lds ago</string>
<string>مُنذُ لَحظة</string>
<key>one</key>
<string>1s ago</string>
<string>مُنذُ ثانية</string>
<key>two</key>
<string>%lds ago</string>
<string>مُنذُ ثانيتين</string>
<key>few</key>
<string>%lds ago</string>
<string>مُنذُ %ld ثوان</string>
<key>many</key>
<string>%lds ago</string>
<string>مُنذُ %ld ثانية</string>
<key>other</key>
<string>%lds ago</string>
<string>مُنذُ %ld ثانية</string>
</dict>
</dict>
</dict>

View File

@ -2,55 +2,55 @@
"common": {
"alerts": {
"common": {
"please_try_again": "الرجاء المحاولة مرة أخرى.",
"please_try_again_later": "الرجاء المحاولة مرة أخرى لاحقاً."
"please_try_again": "يُرجى المحاولة مرة أُخرى.",
"please_try_again_later": "يُرجى المحاولة مرة أُخرى لاحقاً."
},
"sign_up_failure": {
"title": "فشل التسجيل"
"title": "إخفاق في التسجيل"
},
"server_error": {
"title": "خطأ في الخادم"
},
"vote_failure": {
"title": "فشل التصويت",
"poll_ended": "The poll has ended"
"title": "إخفاق في التصويت",
"poll_ended": "انتهى استطلاع الرأي"
},
"discard_post_content": {
"title": "تجاهل المسودة",
"message": "Confirm to discard composed post content."
"title": "التخلص من المسودة",
"message": "أكِّد للتخلص مِن مُحتوى مَنشور مؤلَّف."
},
"publish_post_failure": {
"title": "أخفقت عملية النشر",
"message": "Failed to publish the post.\nPlease check your internet connection.",
"title": "إخفاق في عمليَّة النشر",
"message": "فَشَلَ نَشر المَنشور.\nيُرجى التحقق من اتصالك بالإنترنت.",
"attachments_message": {
"video_attach_with_photo": "Cannot attach a video to a post that already contains images.",
"more_than_one_video": "Cannot attach more than one video."
"video_attach_with_photo": "لا يُمكن إرفاق مقطع مرئي إلى مَنشور يحتوي بالفعل على صُوَر.",
"more_than_one_video": "لا يُمكِنُ إرفاق أكثر مِن مَقطع مرئي واحِد."
}
},
"edit_profile_failure": {
"title": "Edit Profile Error",
"message": "Cannot edit profile. Please try again."
"title": "خطأ في تَحرير الملف الشخصي",
"message": "لا يمكن تعديل الملف الشخصي. يُرجى المحاولة مرة أُخرى."
},
"sign_out": {
"title": "تسجيل الخروج",
"message": "هل أنت متأكد من أنك تريد تسجيل الخروج؟",
"message": "هل أنت متأكد من رغبتك في تسجيل الخروج؟",
"confirm": "تسجيل الخروج"
},
"block_domain": {
"title": "Are you really, really sure you want to block the entire %s? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain and any of your followers from that domain will be removed.",
"block_entire_domain": "حظر النطاق"
"title": "هل أنتَ مُتأكِّدٌ حقًا مِن رغبتك في حظر %s بالكامل؟ في معظم الحالات، يكون مِنَ الكافي والمُفَضَّل استهداف عدد محدود للحظر أو الكتم. لن ترى محتوى من هذا النطاق وسوف يتم إزالة جميع متابعيك المتواجدين فيه.",
"block_entire_domain": "حظر النِطاق"
},
"save_photo_failure": {
"title": "فشل حفظ الصورة",
"message": "Please enable the photo library access permission to save the photo."
"title": "إخفاق في حفظ الصورة",
"message": "يُرجى إتاحة إذن الوصول إلى مكتبة الصور لحفظ الصورة."
},
"delete_post": {
"title": "هل أنت متأكد من أنك تريد حذف هذا المنشور؟",
"title": "هل أنت متأكد من رغبتك في حذف هذا المنشور؟",
"delete": "احذف"
},
"clean_cache": {
"title": "تنظيف ذاكرة التخزين المؤقت",
"message": "تم تنظيف ذاكرة التخزين المؤقت %s بنجاح."
"title": "مَحو ذاكرة التخزين المؤقت",
"message": "تمَّ مَحو ذاكرة التخزين المؤقت %s بنجاح."
}
},
"controls": {
@ -61,30 +61,31 @@
"open": "افتح",
"add": "إضافة",
"remove": "احذف",
"edit": عديل",
"edit": حرير",
"save": "حفظ",
"ok": "حسنًا",
"done": "تم",
"done": "تمّ",
"confirm": "تأكيد",
"continue": "واصل",
"compose": "تأليف",
"cancel": "إلغاء",
"discard": "تجاهل",
"try_again": "حاول مرة أخرى",
"take_photo": "التقط صورة",
"try_again": "المُحاولة مرة أُخرى",
"take_photo": "التقاط صورة",
"save_photo": "حفظ الصورة",
"copy_photo": "نسخ الصورة",
"sign_in": "لِج",
"sign_up": "انشئ حسابًا",
"sign_in": "تسجيل الدخول",
"sign_up": "إنشاء حِساب",
"see_more": "عرض المزيد",
"preview": عاينة",
"share": "شارك",
"share_user": "شارك %s",
"share_post": "شارك المنشور",
"open_in_safari": "افتحه في سفاري",
"preview": ُعاينة",
"share": "المُشارك",
"share_user": "مُشاركة %s",
"share_post": "مشارك المنشور",
"open_in_safari": "الفتح في Safari",
"find_people": "ابحث عن أشخاص لمتابعتهم",
"manually_search": "البحث يدوياً بدلاً من ذلك",
"skip": "تخطي",
"reply": "رد",
"reply": "الرَد",
"report_user": "ابلغ عن %s",
"block_domain": "حظر %s",
"unblock_domain": "إلغاء حظر %s",
@ -100,7 +101,7 @@
"keyboard": {
"common": {
"switch_to_tab": "التبديل إلى %s",
"compose_new_post": "إنشاء منشور جديد",
"compose_new_post": "تأليف منشور جديد",
"show_favorites": "إظهار المفضلة",
"open_settings": "أفتح الإعدادات"
},
@ -111,9 +112,9 @@
"open_author_profile": "افتح الملف التعريفي للمؤلف",
"open_reblogger_profile": "افتح الملف التعريفي لمشارِك المنشور",
"reply_status": "رد على المنشور",
"toggle_reblog": "Toggle Reblog on Post",
"toggle_favorite": "Toggle Favorite on Post",
"toggle_content_warning": "Toggle Content Warning",
"toggle_reblog": "تبديل إعادة تدوين منشور",
"toggle_favorite": "تبديل المفضلة لِمنشور",
"toggle_content_warning": "تبديل تحذير المُحتَوى",
"preview_image": "معاينة الصورة"
},
"segmented_control": {
@ -122,44 +123,44 @@
}
},
"status": {
"user_reblogged": "%s reblogged",
"user_replied_to": "Replied to %s",
"show_post": "Show Post",
"show_user_profile": "Show user profile",
"content_warning": "Content Warning",
"media_content_warning": "Tap anywhere to reveal",
"user_reblogged": "أعادَ %s تدوينها",
"user_replied_to": "رد على %s",
"show_post": "اظهر المنشور",
"show_user_profile": "اظهر الملف التعريفي للمستخدم",
"content_warning": "تحذير عن المحتوى",
"media_content_warning": "انقر على أي مكان للكشف",
"poll": {
"vote": "Vote",
"closed": "Closed"
"vote": "صَوِّت",
"closed": "انتهى"
},
"actions": {
"reply": "Reply",
"reblog": "Reblog",
"unreblog": "Undo reblog",
"favorite": "Favorite",
"unfavorite": "Unfavorite",
"menu": "Menu"
"reply": "رد",
"reblog": "إعادة النشر",
"unreblog": "تراجع عن إعادة النشر",
"favorite": "إضافة إلى المفضلة",
"unfavorite": "إزالة من المفضلة",
"menu": "القائمة"
},
"tag": {
"url": "URL",
"mention": "Mention",
"link": "Link",
"hashtag": "Hashtag",
"url": "عنوان URL",
"mention": "أشر إلى",
"link": "الرابط",
"hashtag": "الوسم",
"email": "البريد الإلكتروني",
"emoji": "Emoji"
"emoji": "إيموجي"
}
},
"friendship": {
"follow": "Follow",
"following": "Following",
"request": "Request",
"pending": "Pending",
"block": "Block",
"block_user": "Block %s",
"block_domain": "Block %s",
"unblock": "Unblock",
"unblock_user": "Unblock %s",
"blocked": "Blocked",
"follow": "اتبع",
"following": "مُتابَع",
"request": "إرسال طَلَب",
"pending": "قيد المُراجعة",
"block": "حظر",
"block_user": "حظر %s",
"block_domain": "حظر %s",
"unblock": "إلغاء الحَظر",
"unblock_user": "إلغاء حظر %s",
"blocked": "محظور",
"mute": "أكتم",
"mute_user": "أكتم %s",
"unmute": "إلغاء الكتم",
@ -168,45 +169,45 @@
"edit_info": "تعديل المعلومات"
},
"timeline": {
"filtered": "Filtered",
"filtered": "مُصفَّى",
"timestamp": {
"now": "الأن"
},
"loader": {
"load_missing_posts": "Load missing posts",
"load_missing_posts": "تحميل المنشورات المَفقودة",
"loading_missing_posts": "تحميل المزيد من المنشورات...",
"show_more_replies": "إظهار المزيد من الردود"
},
"header": {
"no_status_found": "لا توجد هناك منشورات",
"blocking_warning": "You cant view this user's profile\nuntil you unblock them.\nYour profile looks like this to them.",
"user_blocking_warning": "You cant view %ss profile\nuntil you unblock them.\nYour profile looks like this to them.",
"blocked_warning": "You cant view this users profile\nuntil they unblock you.",
"user_blocked_warning": "You cant view %ss profile\nuntil they unblock you.",
"suspended_warning": "This user has been suspended.",
"user_suspended_warning": "%ss account has been suspended."
"blocking_warning": "لا يُمكنك الاطلاع على الملف الشخصي لهذا المُستخدِم\nحتَّى تَرفعَ الحَظر عنه.\nملفًّكَ الشخصي يَظهَرُ بِمثل هذِهِ الحالة بالنسبةِ لَهُ أيضًا.",
"user_blocking_warning": "لا يُمكنك الاطلاع على ملف %s الشخصي\nحتَّى تَرفعَ الحَظر عنه.\nملفًّكَ الشخصي يَظهَرُ بِمثل هذِهِ الحالة بالنسبةِ لَهُ أيضًا.",
"blocked_warning": "لا يُمكِنُكَ عَرض الملف الشخصي لهذا المُستخدِم\nحتَّى يَرفَعَ الحَظر عَنك.",
"user_blocked_warning": "لا يُمكِنُكَ عَرض ملف %s الشخصي\nحتَّى يَرفَعَ الحَظر عَنك.",
"suspended_warning": "تمَّ إيقاف هذا المُستخدِم.",
"user_suspended_warning": "لقد أوقِفَ حِساب %s."
}
}
}
},
"scene": {
"welcome": {
"slogan": "Social networking\nback in your hands."
"slogan": "شبكات التواصل الاجتماعي\nمرة أُخرى بين يديك."
},
"server_picker": {
"title": "Pick a server,\nany server.",
"title": "اِختر خادِم،\nأي خادِم.",
"button": {
"category": {
"all": "الكل",
"all_accessiblity_description": "الفئة: الكل",
"academia": "academia",
"academia": "أكاديمي",
"activism": "للنشطاء",
"food": "الطعام",
"furry": "فروي",
"games": "ألعاب",
"general": "عام",
"journalism": "صحافة",
"lgbt": "lgbt",
"lgbt": "مجتمع الشواذ",
"regional": "اقليمي",
"art": "فن",
"music": "موسيقى",
@ -225,7 +226,7 @@
},
"empty_state": {
"finding_servers": "البحث عن خوادم متوفرة...",
"bad_network": "Something went wrong while loading the data. Check your internet connection.",
"bad_network": "حدث خطأٌ ما أثناء تحميل البيانات. تحقَّق من اتصالك بالإنترنت.",
"no_results": "لا توجد نتائج"
}
},
@ -263,29 +264,29 @@
"reason": "السبب"
},
"reason": {
"blocked": "%s contains a disallowed email provider",
"unreachable": "%s does not seem to exist",
"taken": "%s is already in use",
"reserved": "%s is a reserved keyword",
"accepted": "%s must be accepted",
"blank": "%s is required",
"invalid": "%s is invalid",
"too_long": "%s is too long",
"too_short": "%s is too short",
"inclusion": "%s is not a supported value"
"blocked": "يحتوي %s على موفِّر خدمة بريد إلكتروني غير مسموح به",
"unreachable": "يبدوا أنَّ %s غير موجود",
"taken": "إنَّ %s مُستخدَمٌ بالفعل",
"reserved": "إنَّ %s عبارة عن كلمة مفتاحيَّة محجوزة",
"accepted": "يجب أن يُقبل %s",
"blank": "%s مطلوب",
"invalid": "%s غير صالح",
"too_long": "%s طويل جداً",
"too_short": "%s قصير جدا",
"inclusion": "إنَّ %s قيمة غير مدعومة"
},
"special": {
"username_invalid": "Username must only contain alphanumeric characters and underscores",
"username_too_long": "Username is too long (cant be longer than 30 characters)",
"email_invalid": "This is not a valid email address",
"password_too_short": "Password is too short (must be at least 8 characters)"
"username_invalid": "يُمكِن أن يحتوي اسم المستخدم على أحرف أبجدية، أرقام وشرطات سفلية فقط",
"username_too_long": "اسم المستخدم طويل جداً (يجب ألّا يكون أطول من 30 رمز)",
"email_invalid": "هذا عنوان بريد إلكتروني غير صالح",
"password_too_short": "كلمة المرور قصيرة جداً (يجب أن تكون 8 أحرف على الأقل)"
}
}
},
"server_rules": {
"title": "Some ground rules.",
"subtitle": "These rules are set by the admins of %s.",
"prompt": "By continuing, youre subject to the terms of service and privacy policy for %s.",
"title": "بعض القواعد الأساسية.",
"subtitle": "تم سنّ هذه القواعد من قبل مشرفي %s.",
"prompt": "إن اخترت المواصلة، فإنك تخضع لشروط الخدمة وسياسة الخصوصية لـ %s.",
"terms_of_service": "شروط الخدمة",
"privacy_policy": "سياسة الخصوصية",
"button": {
@ -294,35 +295,35 @@
},
"confirm_email": {
"title": "شيء واحد أخير.",
"subtitle": "We just sent an email to %s,\ntap the link to confirm your account.",
"subtitle": "لقد أرسلنا للتو رسالة بريد إلكتروني إلى %s،\nاضغط على الرابط لتأكيد حسابك.",
"button": {
"open_email_app": "Open Email App",
"dont_receive_email": "I never got an email"
"open_email_app": "افتح تطبيق البريد الإلكتروني",
"dont_receive_email": "لم أستلم أبدًا بريدا إلكترونيا"
},
"dont_receive_email": {
"title": "Check your email",
"description": "Check if your email address is correct as well as your junk folder if you havent.",
"resend_email": "Resend Email"
"title": "تحقق من بريدك الإلكتروني",
"description": "تحقق ممَّ إذا كان عنوان بريدك الإلكتروني صحيحًا وكذلك تأكد مِن مجلد البريد غير الهام إذا لم تكن قد فعلت ذلك.",
"resend_email": "إعادة إرسال البريد الإلكتروني"
},
"open_email_app": {
"title": "Check your inbox.",
"description": "We just sent you an email. Check your junk folder if you havent.",
"title": "تحقَّق من بريدك الوارِد.",
"description": "لقد أرسلنا لك بريدًا إلكترونيًا للتو. تحقق من مجلد البريد غير الهام الخاص بك إذا لم تكن قد فعلت ذلك.",
"mail": "البريد",
"open_email_client": "Open Email Client"
"open_email_client": "فتح عميل البريد الإلكتروني"
}
},
"home_timeline": {
"title": "الخيط الرئيسي",
"navigation_bar_state": {
"offline": "غير متصل",
"new_posts": "See new posts",
"published": "Published!",
"Publishing": "Publishing post..."
"new_posts": "إظهار منشورات جديدة",
"published": "تم نشره!",
"Publishing": "جارٍ نشر المشاركة…"
}
},
"suggestion_account": {
"title": "Find People to Follow",
"follow_explain": "When you follow someone, youll see their posts in your home feed."
"title": "ابحث عن أشخاص لمتابعتهم",
"follow_explain": "عِندَ مُتابَعَتِكَ لأحدِهِم، سَوف تَرى مَنشوراته في تغذيَتِكَ الرئيسة."
},
"compose": {
"title": {
@ -334,54 +335,54 @@
"photo_library": "مكتبة الصور",
"browse": "تصفح"
},
"content_input_placeholder": "ما الذي يجول ببالك",
"content_input_placeholder": "أخبِرنا بِما يَجُولُ فِي ذِهنَك",
"compose_action": "انشر",
"replying_to_user": "رد على %s",
"attachment": {
"photo": "صورة",
"video": "فيديو",
"attachment_broken": "This %s is broken and cant be\nuploaded to Mastodon.",
"description_photo": "Describe the photo for the visually-impaired...",
"description_video": "Describe the video for the visually-impaired..."
"attachment_broken": "هذا ال%s مُعطَّل ويتعذَّر رفعه إلى ماستودون.",
"description_photo": "صِف الصورة للمكفوفين...",
"description_video": "صِف المقطع المرئي للمكفوفين..."
},
"poll": {
"duration_time": "Duration: %s",
"duration_time": "المدة: %s",
"thirty_minutes": "30 دقيقة",
"one_hour": "ساعة واحدة",
"six_hours": "6 ساعات",
"one_day": "يوم واحد",
"three_days": "3 أيام",
"seven_days": "7 أيام",
"option_number": "Option %ld"
"option_number": "الخيار %ld"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
"placeholder": "اكتب تَحذيرًا دَقيقًا هُنا..."
},
"visibility": {
"public": "Public",
"unlisted": "Unlisted",
"private": "Followers only",
"direct": "Only people I mention"
"public": "للعامة",
"unlisted": "غير مُدرَج",
"private": "لمتابعيك فقط",
"direct": "ففط للأشخاص المشار إليهم"
},
"auto_complete": {
"space_to_add": "Space to add"
"space_to_add": "انقر مساحة لإضافتِها"
},
"accessibility": {
"append_attachment": "Add Attachment",
"append_attachment": "إضافة مُرفَق",
"append_poll": "اضافة استطلاع رأي",
"remove_poll": "إزالة الاستطلاع",
"custom_emoji_picker": "منتقي مخصص للإيموجي",
"enable_content_warning": "تنشيط تحذير المحتوى",
"disable_content_warning": "تعطيل تحذير الحتوى",
"post_visibility_menu": "Post Visibility Menu"
"post_visibility_menu": "قائمة ظهور المنشور"
},
"keyboard": {
"discard_post": "Discard Post",
"publish_post": "Publish Post",
"toggle_poll": "Toggle Poll",
"toggle_content_warning": "Toggle Content Warning",
"append_attachment_entry": "Add Attachment - %s",
"select_visibility_entry": "Select Visibility - %s"
"discard_post": "تجاهُل المنشور",
"publish_post": "نَشر المَنشُور",
"toggle_poll": "تبديل الاستطلاع",
"toggle_content_warning": "تبديل تحذير المُحتوى",
"append_attachment_entry": "إضافة مُرفَق - %s",
"select_visibility_entry": "اختر مدى الظهور - %s"
}
},
"profile": {
@ -393,7 +394,7 @@
"fields": {
"add_row": "إضافة صف",
"placeholder": {
"label": "Label",
"label": "التسمية",
"content": "المحتوى"
}
},
@ -405,14 +406,20 @@
"relationship_action_alert": {
"confirm_unmute_user": {
"title": "إلغاء كتم الحساب",
"message": "Confirm to unmute %s"
"message": "أكِّد لرفع كتمْ %s"
},
"confirm_unblock_usre": {
"title": "إلغاء حظر الحساب",
"message": "Confirm to unblock %s"
"message": "أكِّد لرفع حظر %s"
}
}
},
"follower": {
"footer": "لا يُمكِن عَرض المُتابِعين مِنَ الخوادم الأُخرى."
},
"following": {
"footer": "لا يُمكِن عَرض المُتابَعات مِنَ الخوادم الأُخرى."
},
"search": {
"title": "بحث",
"search_bar": {
@ -423,12 +430,12 @@
"button_text": "طالع الكل",
"hash_tag": {
"title": "ذات شعبية على ماستدون",
"description": "Hashtags that are getting quite a bit of attention",
"people_talking": "%s people are talking"
"description": "الوسوم التي تحظى بقدر كبير من الاهتمام",
"people_talking": "%s أشخاص يتحدَّثوا"
},
"accounts": {
"title": "Accounts you might like",
"description": "You may like to follow these accounts",
"title": "حسابات قد تعجبك",
"description": "قد ترغب في متابعة هذه الحسابات",
"follow": "تابع"
}
},
@ -440,34 +447,34 @@
"posts": "المنشورات"
},
"empty_state": {
"no_results": "No results"
"no_results": "ليس هناك أية نتيجة"
},
"recent_search": "Recent searches",
"clear": "Clear"
"recent_search": "عمليات البحث الأخيرة",
"clear": "مَحو"
}
},
"favorite": {
"title": "Your Favorites"
"title": "مفضلتك"
},
"notification": {
"title": {
"Everything": "Everything",
"Mentions": "Mentions"
"Everything": "الكل",
"Mentions": "الإشارات"
},
"user_followed_you": "%s followed you",
"user_favorited your post": "%s favorited your post",
"user_reblogged_your_post": "%s reblogged your post",
"user_mentioned_you": "%s mentioned you",
"user_requested_to_follow_you": "%s requested to follow you",
"user_your_poll_has_ended": "%s Your poll has ended",
"user_followed_you": "يتابعك %s",
"user_favorited your post": "أضاف %s منشورك إلى مفضلته",
"user_reblogged_your_post": "أعاد %s تدوين مشاركتك",
"user_mentioned_you": "أشار إليك %s",
"user_requested_to_follow_you": "طلب %s متابعتك",
"user_your_poll_has_ended": "%s اِنتهى استطلاعُكَ للرأي",
"keyobard": {
"show_everything": "Show Everything",
"show_mentions": "Show Mentions"
"show_everything": "إظهار كل شيء",
"show_mentions": "إظهار الإشارات"
}
},
"thread": {
"back_title": "Post",
"title": "Post from %s"
"back_title": "منشور",
"title": "مَنشور مِن %s"
},
"settings": {
"title": "الإعدادات",
@ -475,44 +482,44 @@
"appearance": {
"title": "المظهر",
"automatic": "تلقائي",
"light": "Always Light",
"dark": "Always Dark"
"light": "مضيءٌ دائمًا",
"dark": "مظلمٌ دائِمًا"
},
"notifications": {
"title": "الإشعارات",
"favorites": "Favorites my post",
"follows": "Follows me",
"boosts": "Reblogs my post",
"mentions": "Mentions me",
"favorites": "الإعجاب بِمنشوراتي",
"follows": "يتابعني",
"boosts": "إعادة تدوين منشوراتي",
"mentions": "الإشارة لي",
"trigger": {
"anyone": "anyone",
"follower": "a follower",
"follow": "anyone I follow",
"noone": "no one",
"title": "Notify me when"
"anyone": "أي شخص",
"follower": "مشترِك",
"follow": "أي شخص أُتابِعُه",
"noone": "لا أحد",
"title": "إشعاري عِندَ"
}
},
"preference": {
"title": "التفضيلات",
"true_black_dark_mode": "True black dark mode",
"disable_avatar_animation": "Disable animated avatars",
"disable_emoji_animation": "Disable animated emojis",
"using_default_browser": "Use default browser to open links"
"true_black_dark_mode": "النمط الأسود الداكِن الحقيقي",
"disable_avatar_animation": "تعطيل الصور الرمزية المتحرِّكة",
"disable_emoji_animation": "تعطيل الرموز التعبيرية المتحرِّكَة",
"using_default_browser": "اِستخدام المتصفح الافتراضي لفتح الروابط"
},
"boring_zone": {
"title": "The Boring Zone",
"title": "المنطقة المملة",
"account_settings": "إعدادات الحساب",
"terms": "شروط الخدمة",
"privacy": "سياسة الخصوصية"
},
"spicy_zone": {
"title": "The Spicy Zone",
"clear": "Clear Media Cache",
"title": "المنطقة الحارة",
"clear": "مسح ذاكرة التخزين المؤقت للوسائط",
"signout": "تسجيل الخروج"
}
},
"footer": {
"mastodon_description": "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء، على غيت هب %s (%s)"
"mastodon_description": "ماستدون برنامج مفتوح المصدر. يمكنك المساهمة، أو الإبلاغ عن تقارير الأخطاء على GitHub في %s (%s)"
},
"keyboard": {
"close_settings_window": "إغلاق نافذة الإعدادات"
@ -522,18 +529,28 @@
"title": "ابلغ عن %s",
"step1": "الخطوة 1 من 2",
"step2": "الخطوة 2 من 2",
"content1": "Are there any other posts youd like to add to the report?",
"content2": "Is there anything the moderators should know about this report?",
"send": "Send Report",
"skip_to_send": "Send without comment",
"text_placeholder": "Type or paste additional comments"
"content1": "هل ترغب في إضافة أي مشاركات أُخرى إلى الشكوى؟",
"content2": "هل هناك أي شيء يجب أن يعرفه المُراقبين حول هذه الشكوى؟",
"send": "إرسال الشكوى",
"skip_to_send": "إرسال بدون تعليق",
"text_placeholder": "اكتب أو الصق تعليقات إضافيَّة"
},
"preview": {
"keyboard": {
"close_preview": "إغلاق المعاينة",
"close_preview": "إغلاق المُعايَنَة",
"show_next": "إظهار التالي",
"show_previous": "إظهار السابق"
}
},
"account_list": {
"tab_bar_hint": "المِلف المُحدَّد حاليًا: %s. انقر نقرًا مزدوجًا ثم اضغط مع الاستمرار لإظهار مُبدِّل الحِساب",
"dismiss_account_switcher": "تجاهُل مبدِّل الحساب",
"add_account": "إضافة حساب"
},
"wizard": {
"new_in_mastodon": "جديد في ماستودون",
"multiple_account_switch_intro_description": "بدِّل بين حسابات متعددة عبر الاستمرار بالضغط على زر الملف الشخصي.",
"accessibility_hint": "انقر نقرًا مزدوجًا لتجاهل النافذة المنبثقة"
}
}
}

View File

@ -1,6 +1,6 @@
{
"NSCameraUsageDescription": "Used to take photo for post status",
"NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library",
"NewPostShortcutItemTitle": "New Post",
"NSCameraUsageDescription": "يُستخدم لالتقاط الصورة عِندَ نشر الحالات",
"NSPhotoLibraryAddUsageDescription": "يُستخدم لحِفظ الصورة في مكتبة الصور",
"NewPostShortcutItemTitle": "منشور جديد",
"SearchShortcutItemTitle": "البحث"
}

View File

@ -2,10 +2,26 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 notificació per llegir</string>
<key>other</key>
<string>%ld notificacions per llegir</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>El límit dentrada supera a %#@character_count@</string>
<string>El límit de la entrada supera a %#@character_count@</string>
<key>character_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -21,7 +37,7 @@
<key>a11y.plural.count.input_limit_remains</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>El límit dentrada continua sent %#@character_count@</string>
<string>El límit de la entrada continua sent %#@character_count@</string>
<key>character_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -95,7 +111,7 @@
<key>one</key>
<string>1 impuls</string>
<key>other</key>
<string>%ld impuls</string>
<string>%ld impulsos</string>
</dict>
</dict>
<key>plural.count.vote</key>
@ -285,9 +301,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>fa 1a</string>
<string>fa 1 any</string>
<key>other</key>
<string>fa %ldy anys</string>
<string>fa %ld anys</string>
</dict>
</dict>
<key>date.month.ago.abbr</key>
@ -301,9 +317,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>fa 1M</string>
<string>fa 1 mes</string>
<key>other</key>
<string>fa %ldM mesos</string>
<string>fa %ld mesos</string>
</dict>
</dict>
<key>date.day.ago.abbr</key>
@ -317,9 +333,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>fa 1d</string>
<string>fa 1 día</string>
<key>other</key>
<string>fa %ldd dies</string>
<string>fa %ld dies</string>
</dict>
</dict>
<key>date.hour.ago.abbr</key>
@ -335,7 +351,7 @@
<key>one</key>
<string>fa 1h</string>
<key>other</key>
<string>fa %ldh hores</string>
<string>fa %ld hores</string>
</dict>
</dict>
<key>date.minute.ago.abbr</key>
@ -349,9 +365,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>fa 1m</string>
<string>fa 1 minut</string>
<key>other</key>
<string>fa %ldm minuts</string>
<string>fa %ld minuts</string>
</dict>
</dict>
<key>date.second.ago.abbr</key>
@ -365,9 +381,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>fa 1s</string>
<string>fa 1 segon</string>
<key>other</key>
<string>fa %lds seg</string>
<string>fa %ld segons</string>
</dict>
</dict>
</dict>

View File

@ -67,6 +67,7 @@
"done": "Fet",
"confirm": "Confirma",
"continue": "Continua",
"compose": "Composa",
"cancel": "Cancel·la",
"discard": "Descarta",
"try_again": "Torna a provar",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Els seguidors d'altres servidors no son mostrats."
},
"following": {
"footer": "Els seguits d'altres servidors no son mostrats."
},
"search": {
"title": "Cerca",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Mostrar Següent",
"show_previous": "Mostrar Anterior"
}
},
"account_list": {
"tab_bar_hint": "Perfil actual seleccionat: %s. Toca dues vegades i manté el dit per a mostrar el commutador de comptes",
"dismiss_account_switcher": "Descartar el commutador de comptes",
"add_account": "Afegir compte"
},
"wizard": {
"new_in_mastodon": "Nou a Mastodon",
"multiple_account_switch_intro_description": "Commuta entre diversos comptes mantenint premut el botó del perfil.",
"accessibility_hint": "Toca dues vegades per descartar l'assistent"
}
}
}

View File

@ -2,6 +2,30 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>zero</key>
<string>%ld unread notification</string>
<key>one</key>
<string>1 unread notification</string>
<key>two</key>
<string>%ld unread notification</string>
<key>few</key>
<string>%ld unread notification</string>
<key>many</key>
<string>%ld unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Done",
"confirm": "Confirm",
"continue": "Continue",
"compose": "Compose",
"cancel": "Cancel",
"discard": "Discard",
"try_again": "Try Again",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Search",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Done",
"confirm": "Confirm",
"continue": "Continue",
"compose": "Compose",
"cancel": "Cancel",
"discard": "Discard",
"try_again": "Try Again",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Search",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 ungelesene Benachrichtigung</string>
<key>other</key>
<string>%ld ungelesene Benachrichtigungen</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Fertig",
"confirm": "Bestätigen",
"continue": "Fortfahren",
"compose": "Compose",
"cancel": "Abbrechen",
"discard": "Verwerfen",
"try_again": "Nochmals versuchen",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Suche",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Nächstes anzeigen",
"show_previous": "Vorheriges anzeigen"
}
},
"account_list": {
"tab_bar_hint": "Aktuell ausgewähltes Profil: %s. Doppeltippen dann gedrückt halten, um den Kontoschalter anzuzeigen",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Konto hinzufügen"
},
"wizard": {
"new_in_mastodon": "Neu in Mastodon",
"multiple_account_switch_intro_description": "Wechsel zwischen mehreren Konten durch drücken der Profil-Schaltfläche.",
"accessibility_hint": "Doppeltippen, um diesen Assistenten zu schließen"
}
}
}

View File

@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Done",
"confirm": "Confirm",
"continue": "Continue",
"compose": "Compose",
"cancel": "Cancel",
"discard": "Discard",
"try_again": "Try Again",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Search",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 notificación sin leer</string>
<key>other</key>
<string>%ld notificaciones sin leer</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Listo",
"confirm": "Confirmar",
"continue": "Continuar",
"compose": "Redactar",
"cancel": "Cancelar",
"discard": "Descartar",
"try_again": "Intentá de nuevo",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "No se muestran los seguidores de otros servidores."
},
"following": {
"footer": "No se muestran las cuentas de otros servidores que seguís."
},
"search": {
"title": "Buscar",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Mostrar siguiente",
"show_previous": "Mostrar anterior"
}
},
"account_list": {
"tab_bar_hint": "Perfil seleccionado actualmente: %s. Tocá dos veces y mantenelo presionado para cambiar de cuenta",
"dismiss_account_switcher": "Descartar cambio de cuenta",
"add_account": "Agregar cuenta"
},
"wizard": {
"new_in_mastodon": "Novedad en Mastodon",
"multiple_account_switch_intro_description": "Cambiá entre varias cuentas manteniendo presionado el botón del perfil.",
"accessibility_hint": "Tocá dos veces para descartar este asistente"
}
}
}

View File

@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Hecho",
"confirm": "Confirmar",
"continue": "Continuar",
"compose": "Redactar",
"cancel": "Cancelar",
"discard": "Descartar",
"try_again": "Inténtalo de nuevo",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "No se muestran los seguidores de otros servidores."
},
"following": {
"footer": "No se muestran los seguidos de otros servidores."
},
"search": {
"title": "Buscar",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Mostrar Siguiente",
"show_previous": "Mostrar Anterior"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,10 +2,26 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 notification non lue</string>
<key>other</key>
<string>%ld notifications non lues</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>Input limit exceeds %#@character_count@</string>
<string>La limite dentrée dépasse %#@character_count@</string>
<key>character_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -13,9 +29,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 character</string>
<string>1 caractère</string>
<key>other</key>
<string>%ld characters</string>
<string>%ld caractères</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_remains</key>
@ -29,9 +45,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 character</string>
<string>1 caractère</string>
<key>other</key>
<string>%ld characters</string>
<string>%ld caractères</string>
</dict>
</dict>
<key>plural.count.metric_formatted.post</key>
@ -61,9 +77,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 post</string>
<string>1 publication</string>
<key>other</key>
<string>%ld posts</string>
<string>%ld publications</string>
</dict>
</dict>
<key>plural.count.favorite</key>
@ -157,9 +173,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 following</string>
<string>1 abonnement</string>
<key>other</key>
<string>%ld following</string>
<string>%ld abonnements</string>
</dict>
</dict>
<key>plural.count.follower</key>
@ -173,9 +189,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 follower</string>
<string>1 abonné·e</string>
<key>other</key>
<string>%ld followers</string>
<string>%ld abonné·e·s</string>
</dict>
</dict>
<key>date.year.left</key>
@ -189,9 +205,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 year left</string>
<string>Il reste 1 an</string>
<key>other</key>
<string>%ld years left</string>
<string>%ld ans restants</string>
</dict>
</dict>
<key>date.month.left</key>
@ -205,9 +221,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 months left</string>
<string>1 mois restant</string>
<key>other</key>
<string>%ld months left</string>
<string>%ld mois restants</string>
</dict>
</dict>
<key>date.day.left</key>
@ -221,9 +237,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 day left</string>
<string>Il reste 1 jour</string>
<key>other</key>
<string>%ld days left</string>
<string>il reste %ld jours</string>
</dict>
</dict>
<key>date.hour.left</key>
@ -237,9 +253,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 hour left</string>
<string>1 heure restante</string>
<key>other</key>
<string>%ld hours left</string>
<string>%ld heures restantes</string>
</dict>
</dict>
<key>date.minute.left</key>
@ -253,9 +269,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 minute left</string>
<string>1 minute restante</string>
<key>other</key>
<string>%ld minutes left</string>
<string>%ld minutes restantes</string>
</dict>
</dict>
<key>date.second.left</key>
@ -269,9 +285,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 second left</string>
<string>Il reste 1 seconde</string>
<key>other</key>
<string>%ld seconds left</string>
<string>%ld secondes restantes</string>
</dict>
</dict>
<key>date.year.ago.abbr</key>
@ -285,9 +301,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1y ago</string>
<string>il y a 1 année</string>
<key>other</key>
<string>%ldy ago</string>
<string>il y a %ld ans</string>
</dict>
</dict>
<key>date.month.ago.abbr</key>
@ -301,9 +317,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1M ago</string>
<string>il y a 1 mois</string>
<key>other</key>
<string>%ldM ago</string>
<string>il y a %ld mois</string>
</dict>
</dict>
<key>date.day.ago.abbr</key>
@ -317,9 +333,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1d ago</string>
<string>il y a 1j</string>
<key>other</key>
<string>%ldd ago</string>
<string>il y a %ldj</string>
</dict>
</dict>
<key>date.hour.ago.abbr</key>
@ -333,9 +349,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1h ago</string>
<string>il y a 1h</string>
<key>other</key>
<string>%ldh ago</string>
<string>il y a %ldh</string>
</dict>
</dict>
<key>date.minute.ago.abbr</key>
@ -349,9 +365,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1m ago</string>
<string>Il y a 1 m</string>
<key>other</key>
<string>%ldm ago</string>
<string>il y a %ld m</string>
</dict>
</dict>
<key>date.second.ago.abbr</key>
@ -365,9 +381,9 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1s ago</string>
<string>Il y a 1 s</string>
<key>other</key>
<string>%lds ago</string>
<string>il y a %ld s</string>
</dict>
</dict>
</dict>

View File

@ -67,6 +67,7 @@
"done": "Terminé",
"confirm": "Confirmer",
"continue": "Continuer",
"compose": "Compose",
"cancel": "Annuler",
"discard": "Abandonner",
"try_again": "Réessayer",
@ -105,10 +106,10 @@
"open_settings": "Ouvrir les paramètres"
},
"timeline": {
"previous_status": "Article précédent",
"next_status": "Article suivant",
"previous_status": "Publication précédente",
"next_status": "Publication suivante",
"open_status": "Ouvrir la publication",
"open_author_profile": "Ouvrir le profil de l'auteur",
"open_author_profile": "Ouvrir le profil de lauteur·rice",
"open_reblogger_profile": "Ouvrir le profil du rebloggeur",
"reply_status": "Répondre à la publication",
"toggle_reblog": "Basculer le reblogue lors de la publication",
@ -122,10 +123,10 @@
}
},
"status": {
"user_reblogged": "%s à reblogué",
"user_reblogged": "%s a reblogué",
"user_replied_to": "À répondu à %s",
"show_post": "Montrer la publication",
"show_user_profile": "Montrer le profil de lutilisateur",
"show_user_profile": "Montrer le profil de lutilisateur·rice",
"content_warning": "Avertissement de contenu",
"media_content_warning": "Tapotez nimporte où pour révéler la publication",
"poll": {
@ -180,9 +181,9 @@
"header": {
"no_status_found": "Aucune publication trouvée",
"blocking_warning": "Vous ne pouvez pas voir le profil de cet utilisateur\n tant que vous ne lavez pas débloqué\nVotre profil ressemble à ça pour lui.",
"user_blocking_warning": "Vous ne pouvez pas voir le profil de %s tant que vous ne lavez pas débloqué\nVotre profil ressemble à ça pour lui.",
"user_blocking_warning": "Vous ne pouvez pas voir le profil de %s\ntant que vous ne lavez pas débloqué\nVotre profil ressemble à ça pour lui.",
"blocked_warning": "Vous ne pouvez pas voir le profil de cet utilisateur\n tant qu'il ne vous aura pas débloqué.",
"user_blocked_warning": "Vous ne pouvez pas voir le profil de %s\n tant qu'il ne vous aura pas débloqué.",
"user_blocked_warning": "Vous ne pouvez pas voir le profil de %s\ntant quil ne vous aura pas débloqué.",
"suspended_warning": "Cet utilisateur a été suspendu.",
"user_suspended_warning": "Le compte de %s à été suspendu."
}
@ -217,7 +218,7 @@
},
"label": {
"language": "LANGUE",
"users": "UTILISATEURS",
"users": "UTILISATEUR·RICE·S",
"category": "CATÉGORIE"
},
"input": {
@ -255,7 +256,7 @@
},
"error": {
"item": {
"username": "Nom d'utilisateur",
"username": "Nom dutilisateur",
"email": "Courriel",
"password": "Mot de passe",
"agreement": "Accord",
@ -370,7 +371,7 @@
"append_attachment": "Joindre un document",
"append_poll": "Ajouter un Sondage",
"remove_poll": "Retirer le sondage",
"custom_emoji_picker": "Sélecteur démojis personnalisé",
"custom_emoji_picker": "Sélecteur démojis personnalisés",
"enable_content_warning": "Basculer lavertissement de contenu",
"disable_content_warning": "Désactiver l'avertissement de contenu",
"post_visibility_menu": "Menu de Visibilité de la publication"
@ -405,7 +406,7 @@
"relationship_action_alert": {
"confirm_unmute_user": {
"title": "Ne plus mettre en sourdine ce compte",
"message": "Êtes-vous sûr de vouloir mettre en sourdine %s"
"message": "Êtes-vous sûr de vouloir désactiver la sourdine de %s"
},
"confirm_unblock_usre": {
"title": "Débloquer le compte",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Les abonné·e·s issus des autres serveurs ne sont pas affiché·e·s."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Rechercher",
"search_bar": {
@ -454,12 +461,12 @@
"Everything": "Tout",
"Mentions": "Mentions"
},
"user_followed_you": "%s followed you",
"user_favorited your post": "%s favorited your post",
"user_reblogged_your_post": "%s reblogged your post",
"user_mentioned_you": "%s mentioned you",
"user_requested_to_follow_you": "%s requested to follow you",
"user_your_poll_has_ended": "%s Your poll has ended",
"user_followed_you": "%s sest abonné à vous",
"user_favorited your post": "%s a mis votre pouet en favori",
"user_reblogged_your_post": "%s a partagé votre publication",
"user_mentioned_you": "%s vous a mentionné",
"user_requested_to_follow_you": "%s a demandé à vous suivre",
"user_your_poll_has_ended": "%s votre sondage est terminé",
"keyobard": {
"show_everything": "Tout Afficher",
"show_mentions": "Afficher les mentions"
@ -496,7 +503,7 @@
"title": "Préférences",
"true_black_dark_mode": "Vrai mode sombre",
"disable_avatar_animation": "Désactiver les avatars animés",
"disable_emoji_animation": "Désactiver les émoticônes animées",
"disable_emoji_animation": "Désactiver les émojis animées",
"using_default_browser": "Utiliser le navigateur par défaut pour ouvrir les liens"
},
"boring_zone": {
@ -534,6 +541,16 @@
"show_next": "Afficher le suivant",
"show_previous": "Afficher le précédent"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Ajouter un compte"
},
"wizard": {
"new_in_mastodon": "Nouveau dans Mastodon",
"multiple_account_switch_intro_description": "Basculez entre plusieurs comptes en appuyant de maniere prolongée sur le bouton profil.",
"accessibility_hint": "Tapotez deux fois pour fermer cet assistant"
}
}
}

View File

@ -2,6 +2,26 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>%ld bhrath nach deach a leughadh</string>
<key>two</key>
<string>%ld bhrath nach deach a leughadh</string>
<key>few</key>
<string>%ld brathan nach deach a leughadh</string>
<key>other</key>
<string>%ld brath nach deach a leughadh</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Deiseil",
"confirm": "Dearbh",
"continue": "Lean air adhart",
"compose": "Sgrìobh",
"cancel": "Sguir dheth",
"discard": "Tilg air falbh",
"try_again": "Feuch ris a-rithist",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Cha dèid luchd-leantainn o fhrithealaichean eile a shealltainn."
},
"following": {
"footer": "Cha dèid cò air a leanas tu air frithealaichean eile a shealltainn."
},
"search": {
"title": "Lorg",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Air adhart",
"show_previous": "Air ais"
}
},
"account_list": {
"tab_bar_hint": "A phròifil air a taghadh: %s. Thoir gnogag dhùbailte is cùm sìos a ghearradh leum gu cunntas eile",
"dismiss_account_switcher": "Leig seachad taghadh a chunntais",
"add_account": "Cuir cunntas ris"
},
"wizard": {
"new_in_mastodon": "Na tha ùr ann am Mastodon",
"multiple_account_switch_intro_description": "Geàrr leum eadar iomadh cunntas le cumail sìos putan na pròifil.",
"accessibility_hint": "Thoir gnogag dhùbailte a leigeil seachad an draoidh seo"
}
}
}

View File

@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Done",
"confirm": "Confirm",
"continue": "Continue",
"compose": "Compose",
"cancel": "Cancel",
"discard": "Discard",
"try_again": "Try Again",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Search",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,6 +2,20 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
@ -69,7 +83,7 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld favorites</string>
<string>%ld favorit</string>
</dict>
</dict>
<key>plural.count.reblog</key>
@ -97,7 +111,7 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld votes</string>
<string>%ld suara</string>
</dict>
</dict>
<key>plural.count.voter</key>
@ -111,7 +125,7 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld voters</string>
<string>%ld pemilih</string>
</dict>
</dict>
<key>plural.people_talking</key>

View File

@ -67,6 +67,7 @@
"done": "Selesai",
"confirm": "Konfirmasi",
"continue": "Lanjut",
"compose": "Compose",
"cancel": "Batal",
"discard": "Discard",
"try_again": "Coba Lagi",
@ -267,7 +268,7 @@
"unreachable": "%s sepertinya tidak ada",
"taken": "%s sudah digunakan",
"reserved": "%s is a reserved keyword",
"accepted": "%s must be accepted",
"accepted": "%s harus diterima",
"blank": "%s diperlukan",
"invalid": "%s tidak valid",
"too_long": "%s terlalu panjang",
@ -355,7 +356,7 @@
"option_number": "Option %ld"
},
"content_warning": {
"placeholder": "Write an accurate warning here..."
"placeholder": "Tulis peringatan yang akurat di sini..."
},
"visibility": {
"public": "Publik",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Cari",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,6 +2,20 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld 件の未読通知</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
@ -13,7 +27,7 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld characters</string>
<string>%ld 文字</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_remains</key>
@ -27,7 +41,7 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld characters</string>
<string>%ld 文字</string>
</dict>
</dict>
<key>plural.count.metric_formatted.post</key>
@ -97,7 +111,7 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld votes</string>
<string>%ld</string>
</dict>
</dict>
<key>plural.count.voter</key>
@ -181,7 +195,7 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld months left</string>
<string>%ldか月前</string>
</dict>
</dict>
<key>date.day.left</key>
@ -265,7 +279,7 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ldM ago</string>
<string>%ld分前</string>
</dict>
</dict>
<key>date.day.ago.abbr</key>

View File

@ -67,6 +67,7 @@
"done": "完了",
"confirm": "確認",
"continue": "続ける",
"compose": "Compose",
"cancel": "キャンセル",
"discard": "破棄",
"try_again": "再実行",
@ -191,7 +192,7 @@
},
"scene": {
"welcome": {
"slogan": "Social networking\nback in your hands."
"slogan": "ソーシャルネットワーキングを、あなたの手の中に."
},
"server_picker": {
"title": "サーバーを選択",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "検索",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "次を見る",
"show_previous": "前を見る"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "アカウントを追加"
},
"wizard": {
"new_in_mastodon": "Mastodon の新機能",
"multiple_account_switch_intro_description": "プロフィールボタンを押して複数のアカウントを切り替えます。",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -0,0 +1,390 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 agahdariya nexwendî</string>
<key>other</key>
<string>%ld agahdariyên nexwendî</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>Sînorê têketinê derbas kir %#@character_count@</string>
<key>character_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 tîp</string>
<key>other</key>
<string>%ld tîp</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_remains</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>Sînorê têketinê %#@character_count@ maye</string>
<key>character_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 tîp</string>
<key>other</key>
<string>%ld tîp</string>
</dict>
</dict>
<key>plural.count.metric_formatted.post</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%@ %#@post_count@</string>
<key>post_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>şandî</string>
<key>other</key>
<string>şandî</string>
</dict>
</dict>
<key>plural.count.post</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@post_count@</string>
<key>post_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 şandî</string>
<key>other</key>
<string>%ld şandî</string>
</dict>
</dict>
<key>plural.count.favorite</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@favorite_count@</string>
<key>favorite_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 hezkirin</string>
<key>other</key>
<string>%ld hezkirin</string>
</dict>
</dict>
<key>plural.count.reblog</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@reblog_count@</string>
<key>reblog_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 ji nû ve nivîsandin</string>
<key>other</key>
<string>%ld ji nû ve nivîsandin</string>
</dict>
</dict>
<key>plural.count.vote</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@vote_count@</string>
<key>vote_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 deng</string>
<key>other</key>
<string>%ld deng</string>
</dict>
</dict>
<key>plural.count.voter</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@voter_count@</string>
<key>voter_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 hilbijêr</string>
<key>other</key>
<string>%ld hilbijêr</string>
</dict>
</dict>
<key>plural.people_talking</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_people_talking@</string>
<key>count_people_talking</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 mirov diaxive</string>
<key>other</key>
<string>%ld mirov diaxive</string>
</dict>
</dict>
<key>plural.count.following</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_following@</string>
<key>count_following</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 dişopîne</string>
<key>other</key>
<string>%ld dişopîne</string>
</dict>
</dict>
<key>plural.count.follower</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_follower@</string>
<key>count_follower</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 şopîner</string>
<key>other</key>
<string>%ld şopîner</string>
</dict>
</dict>
<key>date.year.left</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_year_left@</string>
<key>count_year_left</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 sal berê</string>
<key>other</key>
<string>%ld sal berê</string>
</dict>
</dict>
<key>date.month.left</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_month_left@</string>
<key>count_month_left</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 meh berê</string>
<key>other</key>
<string>%ld meh berê</string>
</dict>
</dict>
<key>date.day.left</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_day_left@</string>
<key>count_day_left</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 roj berê</string>
<key>other</key>
<string>%ld roj berê</string>
</dict>
</dict>
<key>date.hour.left</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_hour_left@</string>
<key>count_hour_left</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 demjimêr berê</string>
<key>other</key>
<string>%ld demjimêr berê</string>
</dict>
</dict>
<key>date.minute.left</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_minute_left@</string>
<key>count_minute_left</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 xulek berê</string>
<key>other</key>
<string>%ld xulek berê</string>
</dict>
</dict>
<key>date.second.left</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_second_left@</string>
<key>count_second_left</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 çirke berê</string>
<key>other</key>
<string>%ld çirke berê</string>
</dict>
</dict>
<key>date.year.ago.abbr</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_year_ago_abbr@</string>
<key>count_year_ago_abbr</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 sal berê</string>
<key>other</key>
<string>%ld sal berê</string>
</dict>
</dict>
<key>date.month.ago.abbr</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_month_ago_abbr@</string>
<key>count_month_ago_abbr</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 xulek berê</string>
<key>other</key>
<string>%ld xulek berê</string>
</dict>
</dict>
<key>date.day.ago.abbr</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_day_ago_abbr@</string>
<key>count_day_ago_abbr</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 roj berê</string>
<key>other</key>
<string>%ld roj berê</string>
</dict>
</dict>
<key>date.hour.ago.abbr</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_hour_ago_abbr@</string>
<key>count_hour_ago_abbr</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 demjimêr berê</string>
<key>other</key>
<string>%ld demjimêr berê</string>
</dict>
</dict>
<key>date.minute.ago.abbr</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_minute_ago_abbr@</string>
<key>count_minute_ago_abbr</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 xulek berê</string>
<key>other</key>
<string>%ld xulek berê</string>
</dict>
</dict>
<key>date.second.ago.abbr</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count_second_ago_abbr@</string>
<key>count_second_ago_abbr</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 çirke berê</string>
<key>other</key>
<string>%ld çirke berê</string>
</dict>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,556 @@
{
"common": {
"alerts": {
"common": {
"please_try_again": "Ji kerema xwe dîsa biceribîne.",
"please_try_again_later": "Ji kerema xwe paşê dîsa biceribîne."
},
"sign_up_failure": {
"title": "Tomarkirin têkçû"
},
"server_error": {
"title": "Çewtiya rajekar"
},
"vote_failure": {
"title": "Dengdayîn têkçû",
"poll_ended": "Rapirsîya qediya"
},
"discard_post_content": {
"title": "Reşnivîsê paşguh bike",
"message": "Bipejrîne ku naveroka şandiyê ya hatiye nivîsandin paşguh bikî."
},
"publish_post_failure": {
"title": "Weşandin têkçû",
"message": "Weşandina şandiyê têkçû.\nJkx girêdana înternetê xwe kontrol bike.",
"attachments_message": {
"video_attach_with_photo": "Nikare vîdyoyekê tevlî şandiyê ku berê wêne tê de heye bike.",
"more_than_one_video": "Nikare ji bêtirî yek vîdyoyekê tevlî şandiyê bike."
}
},
"edit_profile_failure": {
"title": "Di serrastkirina profîlê çewtî",
"message": "Nikare profîlê serrast bike. Jkx dîsa biceribîne."
},
"sign_out": {
"title": "Derkeve",
"message": "Ma tu dixwazî ku derkevî?",
"confirm": "Derkeve"
},
"block_domain": {
"title": "Tu ji xwe bawerî, bi rastî tu dixwazî hemû %s asteng bikî? Di gelek rewşan de asteng kirin an jî bêdeng kirin têrê dike û tê tercîh kirin. Tu nikarî naveroka vê navperê di demnameyê an jî agahdariyên xwe de bibînî. Şopînerên te yê di vê navperê were jêbirin.",
"block_entire_domain": "Navperê asteng bike"
},
"save_photo_failure": {
"title": "Tomarkirina wêneyê têkçû",
"message": "Ji kerema xwe mafê bide gihîştina wênegehê çalak bike da ku wêne werin tomarkirin."
},
"delete_post": {
"title": "Ma tu dixwazî vê şandiyê jê bibî?",
"delete": "Jê bibe"
},
"clean_cache": {
"title": "Pêşbîrê pak bike",
"message": "Pêşbîra %s biserketî hate pakkirin."
}
},
"controls": {
"actions": {
"back": "Vegere",
"next": "Pêş",
"previous": "Paş",
"open": "Veke",
"add": "Tevlî bike",
"remove": "Rake",
"edit": "Serrast bike",
"save": "Tomar bike",
"ok": "BAŞ E",
"done": "Qediya",
"confirm": "Bipejirîne",
"continue": "Bidomîne",
"compose": "Binivîsîne",
"cancel": "Dev jê berde",
"discard": "Biavêje",
"try_again": "Dîsa biceribîne",
"take_photo": "Wêne bikişîne",
"save_photo": "Wêneyê tomar bike",
"copy_photo": "Wêneyê jê bigire",
"sign_in": "Têkeve",
"sign_up": "Tomar bibe",
"see_more": "Bêtir bibîne",
"preview": "Pêşdîtin",
"share": "Parve bike",
"share_user": "%s parve bike",
"share_post": "Şandiyê parve bike",
"open_in_safari": "Di Safariyê de veke",
"find_people": "Mirovan bo şopandinê bibîne",
"manually_search": "Ji devlê bi destan lêgerînê bike",
"skip": "Derbas bike",
"reply": "Bersivê bide",
"report_user": "%s ragihîne",
"block_domain": "%s asteng bike",
"unblock_domain": "%s asteng neke",
"settings": "Sazkarî",
"delete": "Jê bibe"
},
"tabs": {
"home": "Serrûpel",
"search": "Bigere",
"notification": "Agahdarî",
"profile": "Profîl"
},
"keyboard": {
"common": {
"switch_to_tab": "Biguherîne bo %s",
"compose_new_post": "Şandiyeke nû binivsîne",
"show_favorites": "Bijarteyan nîşan bide",
"open_settings": "Sazkariyan Veke"
},
"timeline": {
"previous_status": "Şandeya paş",
"next_status": "Şandiya pêş",
"open_status": "Şandiyê veke",
"open_author_profile": "Profîla nivîskaran veke",
"open_reblogger_profile": "Profîla nivîskaran veke",
"reply_status": "Bersivê bide şandiyê",
"toggle_reblog": "Ji vû nivîsandin di şandiyê de biguherîne",
"toggle_favorite": "Li ser şandiyê bijarte biguherîne",
"toggle_content_warning": "Hişyariya naverokê biguherîne",
"preview_image": "Pêşdîtina wêneyê"
},
"segmented_control": {
"previous_section": "Beşa paş",
"next_section": "Beşa pêş"
}
},
"status": {
"user_reblogged": "%s ji nû ve hate nivîsandin",
"user_replied_to": "Bersiv da %s",
"show_post": "Şandiyê nîşan bide",
"show_user_profile": "Profîla bikarhêner nîşan bide",
"content_warning": "Hişyariya naverokê",
"media_content_warning": "Ji bo eşkerekirinê li derekî bitikîne",
"poll": {
"vote": "Deng bide",
"closed": "Girtî"
},
"actions": {
"reply": "Bersivê bide",
"reblog": "Ji nû ve nivîsandin",
"unreblog": "Ji nû ve nivîsandinê vegere",
"favorite": "Bijarte",
"unfavorite": "Nebijarte",
"menu": "Kulîn"
},
"tag": {
"url": "URL",
"mention": "Qalkirin",
"link": "Girêdan",
"hashtag": "Hashtag",
"email": "E-name",
"emoji": "Emojî"
}
},
"friendship": {
"follow": "Bişopîne",
"following": "Dişopîne",
"request": "Daxwaz bike",
"pending": "Tê nirxandin",
"block": "Asteng bike",
"block_user": "%s asteng bike",
"block_domain": "%s asteng bike",
"unblock": "Astengiyê rake",
"unblock_user": "%s asteng neke",
"blocked": "Astengkirî",
"mute": "Bêdeng bike",
"mute_user": "%s bêdeng bike",
"unmute": "Bêdeng neke",
"unmute_user": "%s bêdeng neke",
"muted": "Bêdengkirî",
"edit_info": "Zanyariyan serrast bike"
},
"timeline": {
"filtered": "Parzûnkirî",
"timestamp": {
"now": "Niha"
},
"loader": {
"load_missing_posts": "Şandiyên wendayî bar bike",
"loading_missing_posts": "Şandiyên wendayî tên barkirin...",
"show_more_replies": "Bêtir bersivan nîşan bide"
},
"header": {
"no_status_found": "Tu şandî nehate dîtin",
"blocking_warning": "Tu nikarî profîla vî/ê bikarhênerî bibînî\nHeya ku tu astengiyê li ser wî/ê ranekî.\nProfîla te ji wan ra wiha xuya dike.",
"user_blocking_warning": "Tu nikarî profîla %s bibînî\nHeya ku tu astengiyê li ser wî/ê ranekî.\nProfîla te ji wan ra wiha xuya dike.",
"blocked_warning": "Tu nikarî profîla vî/ê bikarhênerî bibînî\nheya ku ew astengiyê li ser te rakin.",
"user_blocked_warning": "Tu nikarî profîla %s bibînî\nHeta ku astengîya te rakin.",
"suspended_warning": "Ev bikarhêner hatiye rawestandin.",
"user_suspended_warning": "Ajimêra %s hatiye rawestandin."
}
}
}
},
"scene": {
"welcome": {
"slogan": "Torên civakî\ndi destên te de."
},
"server_picker": {
"title": "Rajekarekê hilbijêre,\nHer kîjan rajekar be.",
"button": {
"category": {
"all": "Hemû",
"all_accessiblity_description": "Beş: Hemû",
"academia": "akademî",
"activism": "çalakî",
"food": "xwarin",
"furry": "furry",
"games": "lîsk",
"general": "giştî",
"journalism": "rojnamevanî",
"lgbt": "lgbt",
"regional": "herêmî",
"art": "huner",
"music": "muzîk",
"tech": "teknolojî"
},
"see_less": "Kêmtir bibîne",
"see_more": "Bêtir bibîne"
},
"label": {
"language": "ZIMAN",
"users": "BIKARHÊNER",
"category": "BEŞ"
},
"input": {
"placeholder": "Rajekarekî bibîne an jî beşdarî ya xwe bibe..."
},
"empty_state": {
"finding_servers": "Peydakirina rajekarên berdest...",
"bad_network": "Di dema barkirina daneyan da çewtî derket. Girêdana xwe ya înternetê kontrol bike.",
"no_results": "Encam tune"
}
},
"register": {
"title": "Ji me re hinekî qala xwe bike.",
"input": {
"avatar": {
"delete": "Jê bibe"
},
"username": {
"placeholder": "navê bikarhêner",
"duplicate_prompt": "Navê vê bikarhêner tê girtin."
},
"display_name": {
"placeholder": "navê nîşanê"
},
"email": {
"placeholder": "e-name"
},
"password": {
"placeholder": "pêborîn",
"hint": "Pêborîna te herî kêm divê ji 8 tîpan pêk bê"
},
"invite": {
"registration_user_invite_request": "Tu çima dixwazî beşdar bibî?"
}
},
"error": {
"item": {
"username": "Navê bikarhêner",
"email": "E-name",
"password": "Pêborîn",
"agreement": "Peyman",
"locale": "Zimanê navrûyê",
"reason": "Sedem"
},
"reason": {
"blocked": "%s peydekerê e-peyamê yê qedexekirî dihewîne",
"unreachable": "%s xuya ye ku tune ye",
"taken": "%s jixwe tê bikaranîn",
"reserved": "%s peyveke parastî ye",
"accepted": "%s divê were pejirandin",
"blank": "%s pêwist e",
"invalid": "%s ne derbasdar e",
"too_long": "%s pir dirêj e",
"too_short": "%s pir kurt e",
"inclusion": "%s ne nirxek piştgirî ye"
},
"special": {
"username_invalid": "Navê bikarhêner divê tenê ji tîpên alfajimarî û binxêz pêk be",
"username_too_long": "Navê bikarhêner pir dirêj e (ji 30 tîpan dirêjtir nabe)",
"email_invalid": "Ev navnîşaneke e-nameyê ne derbasdar e",
"password_too_short": "Pêborîn pir kurt e (divê herî kêm 8 tîp be)"
}
}
},
"server_rules": {
"title": "Hinek rêzikên bingehîn.",
"subtitle": "Ev rêzik ji aliyê rêvebirên %s ve tên sazkirin.",
"prompt": "Bi domandinê, tu ji bo %s di bin mercên bikaranînê û polîtîkaya nepenîtiyê dipejirînî.",
"terms_of_service": "mercên bikaranînê",
"privacy_policy": "polîtikaya nihêniyê",
"button": {
"confirm": "Ez dipejirînim"
}
},
"confirm_email": {
"title": "Tiştekî dawî.",
"subtitle": "Me tenê e-nameyek ji %s re şand,\ngirêdanê bitikne da ku ajimêra xwe bidî piştrastkirin.",
"button": {
"open_email_app": "Sepana e-nameyê veke",
"dont_receive_email": "Min hîç e-nameyeke nesitand"
},
"dont_receive_email": {
"title": "E-nameyê xwe kontrol bike",
"description": "Kontrol bike ka navnîşana e-nameya te rast e û her wiha peldanka xwe ya spam.",
"resend_email": "E-namyê yê dîsa bişîne"
},
"open_email_app": {
"title": "Nameyên xwe yên wergirtî kontrol bike.",
"description": "Me tenê ji te re e-nameyek şand. Heke nehatiye peldanka xwe ya spamê kontrol bike.",
"mail": "E-name",
"open_email_client": "Rajegirê e-nameyê veke"
}
},
"home_timeline": {
"title": "Serrûpel",
"navigation_bar_state": {
"offline": "Derhêl",
"new_posts": "Şandiyên nû bibîne",
"published": "Hate weşandin!",
"Publishing": "Şandî tê weşandin..."
}
},
"suggestion_account": {
"title": "Kesên bo ku bişopînî bibîne",
"follow_explain": "Gava tu kesekî dişopînî, tu yê şandiyê wan di serrûpelê de bibîne."
},
"compose": {
"title": {
"new_post": "Şandiya nû",
"new_reply": "Bersiva nû"
},
"media_selection": {
"camera": "Wêne bikişîne",
"photo_library": "Wênegeh",
"browse": "Bigere"
},
"content_input_placeholder": "Tiştê ku di hişê te de ye binivîsin an jî pêve bike",
"compose_action": "Biweşîne",
"replying_to_user": "bersiv bide %s",
"attachment": {
"photo": "wêne",
"video": "vîdyo",
"attachment_broken": "Ev %s naxebite û nayê barkirin\n li ser Mastodon.",
"description_photo": "Wêneyê ji bo kêmbînên dîtbar bide nasîn...",
"description_video": "Vîdyoyê ji bo kêmbînên dîtbar bide nasîn..."
},
"poll": {
"duration_time": "Dirêjî: %s",
"thirty_minutes": "30 xulek",
"one_hour": "1 Demjimêr",
"six_hours": "6 Demjimêr",
"one_day": "1 Roj",
"three_days": "3 Roj",
"seven_days": "7 Roj",
"option_number": "Vebijêrk %ld"
},
"content_warning": {
"placeholder": "Li vir hişyariyek hûrgilî binivîsine..."
},
"visibility": {
"public": "Gelemperî",
"unlisted": "Nerêzokkirî",
"private": "Tenê şopîneran",
"direct": "Tenê mirovên ku min qalkirî"
},
"auto_complete": {
"space_to_add": "Bicîhkirinê tevlî bike"
},
"accessibility": {
"append_attachment": "Pêvek tevlî bike",
"append_poll": "Rapirsî tevlî bike",
"remove_poll": "Rapirsî rake",
"custom_emoji_picker": "Hilbijêrê emojî yên kesanekirî",
"enable_content_warning": "Hişyariya naverokê çalak bike",
"disable_content_warning": "Hişyariya naverokê neçalak bike",
"post_visibility_menu": "Kulîna xuyabûna şandiyê"
},
"keyboard": {
"discard_post": "Şandî paşguh bike",
"publish_post": "Şandiyê biweşîne",
"toggle_poll": "Rapirsiyê biguherîne",
"toggle_content_warning": "Hişyariya naverokê biguherîne",
"append_attachment_entry": "Pêvek tevlî bike - %s",
"select_visibility_entry": "Xuyabûnê hilbijêre - %s"
}
},
"profile": {
"dashboard": {
"posts": "şandî",
"following": "dişopîne",
"followers": "şopîner"
},
"fields": {
"add_row": "Rêzê tevlî bike",
"placeholder": {
"label": "Nîşan",
"content": "Naverok"
}
},
"segmented_control": {
"posts": "Şandî",
"replies": "Bersiv",
"media": "Medya"
},
"relationship_action_alert": {
"confirm_unmute_user": {
"title": "Ajimêrê bêdeng neke",
"message": "Ji bo vekirina bêdengkirinê bipejirîne %s"
},
"confirm_unblock_usre": {
"title": "Astengiyê li ser ajimêr rake",
"message": "Ji bo rakirina astengkirinê bipejirîne %s"
}
}
},
"follower": {
"footer": "Şopîner ji rajekerên din nayê dîtin."
},
"following": {
"footer": "Şopandin ji rajekerên din nayê dîtin."
},
"search": {
"title": "Bigere",
"search_bar": {
"placeholder": "Li hashtag û bikarhêneran bigere",
"cancel": "Dev jê berde"
},
"recommend": {
"button_text": "Hemûyan bibîne",
"hash_tag": {
"title": "Rojev li ser Mastodon",
"description": "Hashtag ên ku pir balê dikişînin",
"people_talking": "%s kes diaxivin"
},
"accounts": {
"title": "Ajimêrên ku belkî tu jê hez bikî",
"description": "Dibe ku tu bixwazî van ajimêran bişopînî",
"follow": "Bişopîne"
}
},
"searching": {
"segment": {
"all": "Hemû",
"people": "Mirov",
"hashtags": "Hashtag",
"posts": "Şandî"
},
"empty_state": {
"no_results": "Encam tune"
},
"recent_search": "Lêgerînên dawî",
"clear": "Pak bike"
}
},
"favorite": {
"title": "Bijarteyên te"
},
"notification": {
"title": {
"Everything": "Her tişt",
"Mentions": "Qalkirin"
},
"user_followed_you": "%s te şopand",
"user_favorited your post": "%s şandiya te hez kir",
"user_reblogged_your_post": "%s posta we ji nû ve tomar kir",
"user_mentioned_you": "%s qale te kir",
"user_requested_to_follow_you": "%s dixwazê te bişopîne",
"user_your_poll_has_ended": "Rapirsîya te qediya",
"keyobard": {
"show_everything": "Her tiştî nîşan bide",
"show_mentions": "Qalkirinan nîşan bike"
}
},
"thread": {
"back_title": "Şandî",
"title": "Şandî ji %s"
},
"settings": {
"title": "Sazkarî",
"section": {
"appearance": {
"title": "Xuyang",
"automatic": "Xweber",
"light": "Her dem ronî",
"dark": "Her dem tarî"
},
"notifications": {
"title": "Agahdarî",
"favorites": "Şandiyên min hez kir",
"follows": "Min dişopîne",
"boosts": "Şandiya min ji nû ve nivîsand",
"mentions": "Qale min kir",
"trigger": {
"anyone": "her kes",
"follower": "şopînerek",
"follow": "her kesê ku dişopînim",
"noone": "ne yek",
"title": "Min agahdar bike gava"
}
},
"preference": {
"title": "Hilbijarte",
"true_black_dark_mode": "Moda tarî ya reş a rastîn",
"disable_avatar_animation": "Avatarên anîmasyonî neçalak bike",
"disable_emoji_animation": "Emojiyên anîmasyonî neçalak bike",
"using_default_browser": "Ji bo vekirina girêdanan geroka berdest bi kar bîne"
},
"boring_zone": {
"title": "Devera acizker",
"account_settings": "Sazkariyên ajimêr",
"terms": "Mercên bikaranînê",
"privacy": "Polîtikaya nihêniyê"
},
"spicy_zone": {
"title": "Devera germ",
"clear": "Pêşbîra medyayê pak bike",
"signout": "Derkeve"
}
},
"footer": {
"mastodon_description": "Mastodon nermalava çavkaniya vekirî ye. Tu dikarî pirsgirêkan li ser GitHub-ê ragihînî di %s (%s) de"
},
"keyboard": {
"close_settings_window": "Sazkariyên çarçoveyê bigire"
}
},
"report": {
"title": "%s ragihîne",
"step1": "Gav 1 ji 2",
"step2": "Gav 2 ji 2",
"content1": "Şandiyên din hene ku tu dixwazî tevlî ragihandinê bikî?",
"content2": "Derbarê vê ragihandinê de tiştek heye ku divê çavdêr bizanin?",
"send": "Ragihandinê bişîne",
"skip_to_send": "Bêyî şirove bişîne",
"text_placeholder": "Şiroveyên daxwazkirê binivîsine an jî pê ve bike"
},
"preview": {
"keyboard": {
"close_preview": "Pêşdîtin bigire",
"show_next": "A pêş nîşan bide",
"show_previous": "A paş nîşan bide"
}
},
"account_list": {
"tab_bar_hint": "Profîla hilbijartî ya niha: %s. Du caran bitikîne û paşê dest bide ser da ku guhêrbara ajimêr were nîşandan",
"dismiss_account_switcher": "Guherkera ajimêrê paş guh bike",
"add_account": "Ajimêr tevlî bike"
},
"wizard": {
"new_in_mastodon": "Nû di Mastodon de",
"multiple_account_switch_intro_description": "Dest bide ser bişkoja profîlê da ku di navbera gelek ajimêrann de biguherînî.",
"accessibility_hint": "Du caran bitikîne da ku çarçoveyahilpekok ji holê rakî"
}
}
}

View File

@ -0,0 +1,6 @@
{
"NSCameraUsageDescription": "Bo kişandina wêneyê ji bo rewşa şandiyan tê bikaranîn",
"NSPhotoLibraryAddUsageDescription": "Ji bo tomarkirina wêneyê di pirtûkxaneya wêneyan de tê bikaranîn",
"NewPostShortcutItemTitle": "Şandiya nû",
"SearchShortcutItemTitle": "Bigere"
}

View File

@ -2,6 +2,20 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "완료",
"confirm": "확인",
"continue": "계속",
"compose": "Compose",
"cancel": "취소",
"discard": "버리기",
"try_again": "다시 시도",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "검색",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "다음 보기",
"show_previous": "이전 보기"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Klaar",
"confirm": "Bevestigen",
"continue": "Doorgaan",
"compose": "Compose",
"cancel": "Annuleren",
"discard": "Weggooien",
"try_again": "Probeer Opnieuw",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Zoeken",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Volgende",
"show_previous": "Vorige"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Done",
"confirm": "Confirm",
"continue": "Continue",
"compose": "Compose",
"cancel": "Cancel",
"discard": "Discard",
"try_again": "Try Again",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Search",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Done",
"confirm": "Confirm",
"continue": "Continue",
"compose": "Compose",
"cancel": "Cancel",
"discard": "Discard",
"try_again": "Try Again",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Search",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,6 +2,24 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 unread notification</string>
<key>few</key>
<string>%ld unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Done",
"confirm": "Confirm",
"continue": "Continue",
"compose": "Compose",
"cancel": "Cancel",
"discard": "Discard",
"try_again": "Try Again",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Search",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,10 +2,30 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 unread notification</string>
<key>few</key>
<string>%ld unread notification</string>
<key>many</key>
<string>%ld unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>Input limit exceeds %#@character_count@</string>
<string>Лимит превышен на %#@character_count@</string>
<key>character_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -13,19 +33,19 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 character</string>
<string>%ld символ</string>
<key>few</key>
<string>%ld characters</string>
<string>%ld символа</string>
<key>many</key>
<string>%ld characters</string>
<string>%ld символов</string>
<key>other</key>
<string>%ld characters</string>
<string>%ld символа</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_remains</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>Input limit remains %#@character_count@</string>
<string>%#@character_count@</string>
<key>character_count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
@ -33,13 +53,13 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 character</string>
<string>%ld символ остался</string>
<key>few</key>
<string>%ld characters</string>
<string>%ld символа осталось</string>
<key>many</key>
<string>%ld characters</string>
<string>%ld символов осталось</string>
<key>other</key>
<string>%ld characters</string>
<string>%ld символа осталось</string>
</dict>
</dict>
<key>plural.count.metric_formatted.post</key>
@ -53,13 +73,13 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>post</string>
<string>пост</string>
<key>few</key>
<string>posts</string>
<string>поста</string>
<key>many</key>
<string>posts</string>
<string>постов</string>
<key>other</key>
<string>posts</string>
<string>поста</string>
</dict>
</dict>
<key>plural.count.post</key>
@ -133,13 +153,13 @@
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 vote</string>
<string>%ld голос</string>
<key>few</key>
<string>%ld votes</string>
<string>%ld голоса</string>
<key>many</key>
<string>%ld votes</string>
<string>%ld голосов</string>
<key>other</key>
<string>%ld votes</string>
<string>%ld голоса</string>
</dict>
</dict>
<key>plural.count.voter</key>

View File

@ -67,6 +67,7 @@
"done": "Готово",
"confirm": "Подтвердить",
"continue": "Продолжить",
"compose": "Compose",
"cancel": "Отмена",
"discard": "Отмена",
"try_again": "Попробовать снова",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Поиск",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Следующее изображение",
"show_previous": "Предыдущее изображение"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,5 +2,5 @@
"NSCameraUsageDescription": "Used to take photo for post status",
"NSPhotoLibraryAddUsageDescription": "Used to save photo into the Photo Library",
"NewPostShortcutItemTitle": "New Post",
"SearchShortcutItemTitle": "Search"
"SearchShortcutItemTitle": "Поиск"
}

View File

@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Done",
"confirm": "Confirm",
"continue": "Fortsätt",
"compose": "Compose",
"cancel": "Avbryt",
"discard": "Discard",
"try_again": "Försök igen",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Search",
"search_bar": {
@ -454,12 +461,12 @@
"Everything": "Everything",
"Mentions": "Mentions"
},
"user_followed_you": "%s followed you",
"user_followed_you": "%s följde dig",
"user_favorited your post": "%s favorited your post",
"user_reblogged_your_post": "%s reblogged your post",
"user_mentioned_you": "%s mentioned you",
"user_requested_to_follow_you": "%s requested to follow you",
"user_your_poll_has_ended": "%s Your poll has ended",
"user_mentioned_you": "%s nämnde dig",
"user_requested_to_follow_you": "%s har begärt att följa dig",
"user_your_poll_has_ended": "%s Omröstningen har avslutats",
"keyobard": {
"show_everything": "Show Everything",
"show_mentions": "Show Mentions"
@ -534,6 +541,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Lägg till konto"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,6 +2,22 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>one</key>
<string>1 unread notification</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Done",
"confirm": "Confirm",
"continue": "Fortsätt",
"compose": "Compose",
"cancel": "Avbryt",
"discard": "Discard",
"try_again": "Försök igen",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Search",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Lägg till konto"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -2,6 +2,20 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld การแจ้งเตือนที่ยังไม่ได้อ่าน</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "เสร็จสิ้น",
"confirm": "ยืนยัน",
"continue": "ดำเนินการต่อ",
"compose": "เขียน",
"cancel": "ยกเลิก",
"discard": "ละทิ้ง",
"try_again": "ลองอีกครั้ง",
@ -179,10 +180,10 @@
},
"header": {
"no_status_found": "ไม่พบโพสต์",
"blocking_warning": "You cant view this user's profile\nuntil you unblock them.\nYour profile looks like this to them.",
"user_blocking_warning": "You cant view %ss profile\nuntil you unblock them.\nYour profile looks like this to them.",
"blocked_warning": "You cant view this users profile\nuntil they unblock you.",
"user_blocked_warning": "You cant view %ss profile\nuntil they unblock you.",
"blocking_warning": "คุณไม่สามารถดูโปรไฟล์ของผู้ใช้นี้\nจนกว่าคุณจะเลิกปิดกั้นผู้ใช้นี้\nผู้ใช้นี้เห็นโปรไฟล์ของคุณเหมือนกับที่คุณเห็น",
"user_blocking_warning": "คุณไม่สามารถดูโปรไฟล์ของ %s\nจนกว่าคุณจะเลิกปิดกั้นผู้ใช้นี้\nผู้ใช้นี้เห็นโปรไฟล์ของคุณเหมือนกับที่คุณเห็น",
"blocked_warning": "คุณไม่สามารถดูโปรไฟล์ของผู้ใช้นี้\nจนกว่าผู้ใช้นี้จะเลิกปิดกั้นคุณ",
"user_blocked_warning": "คุณไม่สามารถดูโปรไฟล์ของ %s\nจนกว่าผู้ใช้นี้จะเลิกปิดกั้นคุณ",
"suspended_warning": "ผู้ใช้นี้ถูกระงับการใช้งาน",
"user_suspended_warning": "บัญชีของ %s ถูกระงับการใช้งาน"
}
@ -210,7 +211,7 @@
"regional": "ภูมิภาค",
"art": "ศิลปะ",
"music": "ดนตรี",
"tech": "tech"
"tech": "เทคโนโลยี"
},
"see_less": "ดูน้อยลง",
"see_more": "ดูเพิ่มเติม"
@ -285,7 +286,7 @@
"server_rules": {
"title": "กฎพื้นฐานบางประการ",
"subtitle": "กฎเหล่านี้ถูกตั้งโดยผู้ดูแลของ %s",
"prompt": "By continuing, youre subject to the terms of service and privacy policy for %s.",
"prompt": "เมื่อคุณดำเนินการต่อ คุณอยู่ภายใต้เงื่อนไขการให้บริการและนโยบายความเป็นส่วนตัวสำหรับ %s",
"terms_of_service": "เงื่อนไขการให้บริการ",
"privacy_policy": "นโยบายความเป็นส่วนตัว",
"button": {
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "ไม่ได้แสดงผู้ติดตามจากเซิร์ฟเวอร์อื่น ๆ"
},
"following": {
"footer": "ไม่ได้แสดงการติดตามจากเซิร์ฟเวอร์อื่น ๆ"
},
"search": {
"title": "ค้นหา",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "แสดงถัดไป",
"show_previous": "แสดงก่อนหน้า"
}
},
"account_list": {
"tab_bar_hint": "โปรไฟล์ที่เลือกในปัจจุบัน: %s แตะสองครั้งแล้วกดค้างไว้เพื่อแสดงตัวสลับบัญชี",
"dismiss_account_switcher": "ปิดตัวสลับบัญชี",
"add_account": "เพิ่มบัญชี"
},
"wizard": {
"new_in_mastodon": "มาใหม่ใน Mastodon",
"multiple_account_switch_intro_description": "สลับระหว่างหลายบัญชีโดยกดปุ่มโปรไฟล์ค้างไว้",
"accessibility_hint": "แตะสองครั้งเพื่อปิดตัวช่วยสร้างนี้"
}
}
}

View File

@ -2,6 +2,20 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld 条未读通知</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "完成",
"confirm": "确认",
"continue": "继续",
"compose": "撰写",
"cancel": "取消",
"discard": "放弃",
"try_again": "再试一次",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "不会显示来自其它服务器的关注者"
},
"following": {
"footer": "不会显示来自其它服务器的关注"
},
"search": {
"title": "搜索",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "显示下一个",
"show_previous": "显示前一个"
}
},
"account_list": {
"tab_bar_hint": "当前账户:%s。 双击并按住来打开账户切换页面",
"dismiss_account_switcher": "关闭账户切换页面",
"add_account": "添加账户"
},
"wizard": {
"new_in_mastodon": "新功能",
"multiple_account_switch_intro_description": "按住个人资料标签按钮,即可在多个账户之间进行切换。",
"accessibility_hint": "双击关闭此向导"
}
}
}

View File

@ -2,6 +2,20 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>a11y.plural.count.unread.notification</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@notification_count_unread_notification@</string>
<key>notification_count_unread_notification</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>ld</string>
<key>other</key>
<string>%ld unread notification</string>
</dict>
</dict>
<key>a11y.plural.count.input_limit_exceeds</key>
<dict>
<key>NSStringLocalizedFormatKey</key>

View File

@ -67,6 +67,7 @@
"done": "Done",
"confirm": "Confirm",
"continue": "Continue",
"compose": "Compose",
"cancel": "Cancel",
"discard": "Discard",
"try_again": "Try Again",
@ -413,6 +414,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Search",
"search_bar": {
@ -534,6 +541,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

View File

@ -67,6 +67,7 @@
"done": "Done",
"confirm": "Confirm",
"continue": "Continue",
"compose": "Compose",
"cancel": "Cancel",
"discard": "Discard",
"try_again": "Try Again",
@ -81,6 +82,7 @@
"share_user": "Share %s",
"share_post": "Share Post",
"open_in_safari": "Open in Safari",
"open_in_browser": "Open in Browser",
"find_people": "Find people to follow",
"manually_search": "Manually search instead",
"skip": "Skip",
@ -413,6 +415,12 @@
}
}
},
"follower": {
"footer": "Followers from other servers are not displayed."
},
"following": {
"footer": "Follows from other servers are not displayed."
},
"search": {
"title": "Search",
"search_bar": {
@ -534,6 +542,16 @@
"show_next": "Show Next",
"show_previous": "Show Previous"
}
},
"account_list": {
"tab_bar_hint": "Current selected profile: %s. Double tap then hold to show account switcher",
"dismiss_account_switcher": "Dismiss Account Switcher",
"add_account": "Add Account"
},
"wizard": {
"new_in_mastodon": "New in Mastodon",
"multiple_account_switch_intro_description": "Switch between multiple accounts by holding the profile button.",
"accessibility_hint": "Double tap to dismiss this wizard"
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -7,87 +7,92 @@
<key>AppShared.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>60</integer>
<integer>44</integer>
</dict>
<key>CoreDataStack.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>62</integer>
<integer>45</integer>
</dict>
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>11</integer>
<integer>4</integer>
</dict>
<key>Mastodon - RTL.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>12</integer>
<integer>17</integer>
</dict>
<key>Mastodon - Release.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>10</integer>
<integer>3</integer>
</dict>
<key>Mastodon - ar.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>7</integer>
<integer>11</integer>
</dict>
<key>Mastodon - ca.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>32</integer>
<integer>23</integer>
</dict>
<key>Mastodon - de.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>8</integer>
<integer>13</integer>
</dict>
<key>Mastodon - en.xcscheme_^#shared#^_</key>
<key>Mastodon - double length.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
</dict>
<key>Mastodon - es-419.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>5</integer>
</dict>
<key>Mastodon - es.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>4</integer>
</dict>
<key>Mastodon - fr.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>6</integer>
</dict>
<key>Mastodon - jp.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>27</integer>
</dict>
<key>Mastodon - nl.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>9</integer>
</dict>
<key>Mastodon - ru.xcscheme_^#shared#^_</key>
<key>Mastodon - en.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
<key>Mastodon - es-419.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>9</integer>
</dict>
<key>Mastodon - es.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>8</integer>
</dict>
<key>Mastodon - fr.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>10</integer>
</dict>
<key>Mastodon - jp.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>19</integer>
</dict>
<key>Mastodon - nl.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>15</integer>
</dict>
<key>Mastodon - ru.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>5</integer>
</dict>
<key>Mastodon - th.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
<integer>6</integer>
</dict>
<key>Mastodon - zh_Hans.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>30</integer>
<integer>21</integer>
</dict>
<key>Mastodon.xcscheme_^#shared#^_</key>
<dict>
@ -97,7 +102,7 @@
<key>MastodonIntent.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>56</integer>
<integer>43</integer>
</dict>
<key>MastodonIntents.xcscheme_^#shared#^_</key>
<dict>
@ -112,12 +117,12 @@
<key>NotificationService.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>13</integer>
<integer>7</integer>
</dict>
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>58</integer>
<integer>42</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>

View File

@ -6,8 +6,8 @@
"repositoryURL": "https://github.com/Alamofire/Alamofire.git",
"state": {
"branch": null,
"revision": "f96b619bcb2383b43d898402283924b80e2c4bae",
"version": "5.4.3"
"revision": "d120af1e8638c7da36c8481fd61a66c0c08dc4fc",
"version": "5.4.4"
}
},
{
@ -69,8 +69,8 @@
"repositoryURL": "https://github.com/MainasuK/FPSIndicator.git",
"state": {
"branch": null,
"revision": "b2a002d689c400485f2ba41f9e71e15f7b99764a",
"version": "1.0.1"
"revision": "e4a5067ccd5293b024c767f09e51056afd4a4796",
"version": "1.1.0"
}
},
{
@ -96,8 +96,8 @@
"repositoryURL": "https://github.com/TwidereProject/MetaTextKit.git",
"state": {
"branch": null,
"revision": "a5f412b72fc08cd1348e2388fc7ec326365e1823",
"version": "2.1.1"
"revision": "7af4182f64329440a4656f2cba307cb5848e496a",
"version": "2.1.2"
}
},
{
@ -105,8 +105,8 @@
"repositoryURL": "https://github.com/kean/Nuke.git",
"state": {
"branch": null,
"revision": "3bd3a1765bdf62d561d4c2e10e1c4fc7a010f44e",
"version": "10.3.2"
"revision": "0db18dd34998cca18e9a28bcee136f84518007a0",
"version": "10.4.1"
}
},
{
@ -127,13 +127,22 @@
"version": "3.6.2"
}
},
{
"package": "PanModal",
"repositoryURL": "https://github.com/slackhq/PanModal.git",
"state": {
"branch": null,
"revision": "b012aecb6b67a8e46369227f893c12544846613f",
"version": "1.2.7"
}
},
{
"package": "SDWebImage",
"repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
"state": {
"branch": null,
"revision": "76dd4b49110b8624317fc128e7fa0d8a252018bc",
"version": "5.11.1"
"revision": "a72df4849408da7e5d3c1b586797b7c601c41d1b",
"version": "5.12.1"
}
},
{
@ -141,8 +150,8 @@
"repositoryURL": "https://github.com/apple/swift-collections.git",
"state": {
"branch": null,
"revision": "0959ba76a1d4a98fd11163aa83fd49c25b93bfae",
"version": "0.0.5"
"revision": "9d8719c8bebdc79740b6969c912ac706eb721d7a",
"version": "0.0.7"
}
},
{
@ -150,8 +159,8 @@
"repositoryURL": "https://github.com/apple/swift-nio.git",
"state": {
"branch": null,
"revision": "8da5c5a4e6c5084c296b9f39dc54f00be146e0fa",
"version": "1.14.2"
"revision": "546610d52b19be3e19935e0880bb06b9c03f5cef",
"version": "1.14.4"
}
},
{
@ -207,15 +216,6 @@
"revision": "dad97167bf1be16aeecd109130900995dd01c515",
"version": "2.6.0"
}
},
{
"package": "UITextView+Placeholder",
"repositoryURL": "https://github.com/MainasuK/UITextView-Placeholder",
"state": {
"branch": null,
"revision": "20f513ded04a040cdf5467f0891849b1763ede3b",
"version": "1.4.1"
}
}
]
},

View File

@ -5,24 +5,132 @@
// Created by Cirno MainasuK on 2021-1-27.
import UIKit
import Combine
import SafariServices
import CoreDataStack
import MastodonSDK
import PanModal
final public class SceneCoordinator {
private var disposeBag = Set<AnyCancellable>()
private weak var scene: UIScene!
private weak var sceneDelegate: SceneDelegate!
private weak var appContext: AppContext!
private(set) weak var tabBarController: MainTabBarController!
let id = UUID().uuidString
private(set) weak var tabBarController: MainTabBarController!
private(set) weak var splitViewController: RootSplitViewController?
private(set) var wizardViewController: WizardViewController?
private(set) var secondaryStackHashValues = Set<Int>()
init(scene: UIScene, sceneDelegate: SceneDelegate, appContext: AppContext) {
self.scene = scene
self.sceneDelegate = sceneDelegate
self.appContext = appContext
scene.session.sceneCoordinator = self
appContext.notificationService.requestRevealNotificationPublisher
.receive(on: DispatchQueue.main)
.compactMap { [weak self] pushNotification -> AnyPublisher<MastodonPushNotification?, Never> in
guard let self = self else { return Just(nil).eraseToAnyPublisher() }
// skip if no available account
guard let currentActiveAuthenticationBox = appContext.authenticationService.activeMastodonAuthenticationBox.value else {
return Just(nil).eraseToAnyPublisher()
}
let accessToken = pushNotification._accessToken // use raw accessToken value without normalize
if currentActiveAuthenticationBox.userAuthorization.accessToken == accessToken {
// do nothing if notification for current account
return Just(pushNotification).eraseToAnyPublisher()
} else {
// switch to notification's account
let request = MastodonAuthentication.sortedFetchRequest
request.predicate = MastodonAuthentication.predicate(userAccessToken: accessToken)
request.returnsObjectsAsFaults = false
request.fetchLimit = 1
do {
guard let authentication = try appContext.managedObjectContext.fetch(request).first else {
return Just(nil).eraseToAnyPublisher()
}
let domain = authentication.domain
let userID = authentication.userID
return appContext.authenticationService.activeMastodonUser(domain: domain, userID: userID)
.receive(on: DispatchQueue.main)
.map { [weak self] result -> MastodonPushNotification? in
guard let self = self else { return nil }
switch result {
case .success:
// reset view hierarchy
self.setup()
return pushNotification
case .failure:
return nil
}
}
.delay(for: 1, scheduler: DispatchQueue.main) // set delay to slow transition (not must)
.eraseToAnyPublisher()
} catch {
assertionFailure(error.localizedDescription)
return Just(nil).eraseToAnyPublisher()
}
}
}
.switchToLatest()
.receive(on: DispatchQueue.main)
.sink { [weak self] pushNotification in
guard let self = self else { return }
guard let pushNotification = pushNotification else { return }
// redirect to notification tab
self.switchToTabBar(tab: .notification)
// Delay in next run loop
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
// Note:
// show (push) on phone and pad
let from: UIViewController? = {
if let splitViewController = self.splitViewController {
if splitViewController.compactMainTabBarViewController.topMost?.view.window != nil {
// compact
return splitViewController.compactMainTabBarViewController.topMost
} else {
// expand
return splitViewController.contentSplitViewController.mainTabBarController.topMost
}
} else {
return self.tabBarController.topMost
}
}()
// show notification related content
guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: pushNotification.notificationType) else { return }
let notificationID = String(pushNotification.notificationID)
switch type {
case .follow:
let profileViewModel = RemoteProfileViewModel(context: appContext, notificationID: notificationID)
self.present(scene: .profile(viewModel: profileViewModel), from: from, transition: .show)
case .followRequest:
// do nothing
break
case .mention, .reblog, .favourite, .poll, .status:
let threadViewModel = RemoteThreadViewModel(context: appContext, notificationID: notificationID)
self.present(scene: .thread(viewModel: threadViewModel), from: from, transition: .show)
case ._other:
assertionFailure()
break
}
} // end DispatchQueue.main.async
}
.store(in: &disposeBag)
}
}
@ -31,6 +139,8 @@ extension SceneCoordinator {
case show // push
case showDetail // replace
case modal(animated: Bool, completion: (() -> Void)? = nil)
case popover(sourceView: UIView)
case panModal
case custom(transitioningDelegate: UIViewControllerTransitioningDelegate)
case customPush
case safariPresent(animated: Bool, completion: (() -> Void)? = nil)
@ -66,9 +176,12 @@ extension SceneCoordinator {
case hashtagTimeline(viewModel: HashtagTimelineViewModel)
// profile
case accountList
case profile(viewModel: ProfileViewModel)
case favorite(viewModel: FavoriteViewModel)
case follower(viewModel: FollowerListViewModel)
case following(viewModel: FollowingListViewModel)
// setting
case settings(viewModel: SettingsViewModel)
@ -109,9 +222,34 @@ extension SceneCoordinator {
extension SceneCoordinator {
func setup() {
let viewController = MainTabBarController(context: appContext, coordinator: self)
sceneDelegate.window?.rootViewController = viewController
tabBarController = viewController
let rootViewController: UIViewController
switch UIDevice.current.userInterfaceIdiom {
case .phone:
let viewController = MainTabBarController(context: appContext, coordinator: self)
self.splitViewController = nil
self.tabBarController = viewController
rootViewController = viewController
default:
let splitViewController = RootSplitViewController(context: appContext, coordinator: self)
self.splitViewController = splitViewController
self.tabBarController = splitViewController.contentSplitViewController.mainTabBarController
rootViewController = splitViewController
}
let wizardViewController = WizardViewController()
if !wizardViewController.items.isEmpty,
let delegate = rootViewController as? WizardViewControllerDelegate
{
// do not add as child view controller.
// otherwise, the tab bar controller will add as a new tab
wizardViewController.delegate = delegate
wizardViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
wizardViewController.view.frame = rootViewController.view.bounds
rootViewController.view.addSubview(wizardViewController.view)
self.wizardViewController = wizardViewController
}
sceneDelegate.window?.rootViewController = rootViewController
}
func setupOnboardingIfNeeds(animated: Bool) {
@ -165,8 +303,8 @@ extension SceneCoordinator {
switch transition {
case .show:
presentingViewController.show(viewController, sender: sender)
case .showDetail:
secondaryStackHashValues.insert(viewController.hashValue)
let navigationController = AdaptiveStatusBarStyleNavigationController(rootViewController: viewController)
presentingViewController.showDetailViewController(navigationController, sender: sender)
@ -183,11 +321,27 @@ extension SceneCoordinator {
modalNavigationController.presentationController?.delegate = adaptivePresentationControllerDelegate
}
presentingViewController.present(modalNavigationController, animated: animated, completion: completion)
case .panModal:
guard let panModalPresentable = viewController as? PanModalPresentable & UIViewController else {
assertionFailure()
return nil
}
// https://github.com/slackhq/PanModal/issues/74#issuecomment-572426441
panModalPresentable.modalPresentationStyle = .custom
panModalPresentable.modalPresentationCapturesStatusBarAppearance = true
panModalPresentable.transitioningDelegate = PanModalPresentationDelegate.default
presentingViewController.present(panModalPresentable, animated: true, completion: nil)
//presentingViewController.presentPanModal(panModalPresentable)
case .popover(let sourceView):
viewController.modalPresentationStyle = .popover
viewController.popoverPresentationController?.sourceView = sourceView
(splitViewController ?? presentingViewController)?.present(viewController, animated: true, completion: nil)
case .custom(let transitioningDelegate):
viewController.modalPresentationStyle = .custom
viewController.transitioningDelegate = transitioningDelegate
sender?.present(viewController, animated: true, completion: nil)
(splitViewController ?? presentingViewController)?.present(viewController, animated: true, completion: nil)
case .customPush:
// set delegate in view controller
@ -215,7 +369,13 @@ extension SceneCoordinator {
}
func switchToTabBar(tab: MainTabBarController.Tab) {
splitViewController?.contentSplitViewController.currentSupplementaryTab = tab
splitViewController?.compactMainTabBarViewController.selectedIndex = tab.rawValue
splitViewController?.compactMainTabBarViewController.currentTab.value = tab
tabBarController.selectedIndex = tab.rawValue
tabBarController.currentTab.value = tab
}
}
@ -273,6 +433,9 @@ private extension SceneCoordinator {
let _viewController = HashtagTimelineViewController()
_viewController.viewModel = viewModel
viewController = _viewController
case .accountList:
let _viewController = AccountListViewController()
viewController = _viewController
case .profile(let viewModel):
let _viewController = ProfileViewController()
_viewController.viewModel = viewModel
@ -281,6 +444,14 @@ private extension SceneCoordinator {
let _viewController = FavoriteViewController()
_viewController.viewModel = viewModel
viewController = _viewController
case .follower(let viewModel):
let _viewController = FollowerListViewController()
_viewController.viewModel = viewModel
viewController = _viewController
case .following(let viewModel):
let _viewController = FollowingListViewController()
_viewController.viewModel = viewModel
viewController = _viewController
case .suggestionAccount(let viewModel):
let _viewController = SuggestionAccountViewController()
_viewController.viewModel = viewModel

View File

@ -32,7 +32,7 @@ open class TableNodeDiffableDataSource<SectionIdentifierType: Hashable, ItemIden
self.cellProvider = cellProvider
super.init()
tableNode.dataSource = self
tableNode.delegate = self
}
/// Applies given snapshot to perform automatic diffing update.

View File

@ -10,7 +10,7 @@ import Foundation
enum NotificationItem {
case notification(objectID: NSManagedObjectID, attribute: Item.StatusAttribute)
case notificationStatus(objectID: NSManagedObjectID, attribute: Item.StatusAttribute) // display notification status without card wrapper
case bottomLoader
}
@ -19,6 +19,8 @@ extension NotificationItem: Equatable {
switch (lhs, rhs) {
case (.notification(let idLeft, _), .notification(let idRight, _)):
return idLeft == idRight
case (.notificationStatus(let idLeft, _), .notificationStatus(let idRight, _)):
return idLeft == idRight
case (.bottomLoader, .bottomLoader):
return true
default:
@ -32,6 +34,8 @@ extension NotificationItem: Hashable {
switch self {
case .notification(let id, _):
hasher.combine(id)
case .notificationStatus(let id, _):
hasher.combine(id)
case .bottomLoader:
hasher.combine(String(describing: NotificationItem.bottomLoader.self))
}
@ -43,6 +47,8 @@ extension NotificationItem {
switch self {
case .notification(let objectID, _):
return .mastodonNotification(objectID: objectID)
case .notificationStatus(let objectID, _):
return .mastodonNotification(objectID: objectID)
case .bottomLoader:
return nil
}

View File

@ -0,0 +1,16 @@
//
// UserItem.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-11-1.
//
import Foundation
import CoreData
enum UserItem: Hashable {
case follower(objectID: NSManagedObjectID)
case following(objectID: NSManagedObjectID)
case bottomLoader
case bottomHeader(text: String)
}

View File

@ -32,24 +32,8 @@ extension SearchHistorySection {
}
return cell
case .status:
// Should not show status in the history list
return UITableViewCell()
// let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell
// if let status = try? dependency.context.managedObjectContext.existingObject(with: statusObjectID) as? Status {
// let activeMastodonAuthenticationBox = dependency.context.authenticationService.activeMastodonAuthenticationBox.value
// let requestUserID = activeMastodonAuthenticationBox?.userID ?? ""
// StatusSection.configure(
// cell: cell,
// tableView: tableView,
// timelineContext: .search,
// dependency: dependency,
// readableLayoutFrame: tableView.readableContentGuide.layoutFrame,
// status: status,
// requestUserID: requestUserID,
// statusItemAttribute: attribute
// )
// }
// cell.delegate = statusTableViewCellDelegate
// return cell
} // end switch
} // end UITableViewDiffableDataSource
} // end func

View File

@ -41,21 +41,17 @@ extension SettingsSection {
switch item {
case .appearance(let objectID):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsAppearanceTableViewCell.self), for: indexPath) as! SettingsAppearanceTableViewCell
managedObjectContext.performAndWait {
let setting = managedObjectContext.object(with: objectID) as! Setting
cell.update(with: setting.appearance)
ManagedObjectObserver.observe(object: setting)
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { _ in
// do nothing
}, receiveValue: { [weak cell] change in
guard let cell = cell else { return }
guard case .update(let object) = change.changeType,
let setting = object as? Setting else { return }
cell.update(with: setting.appearance)
})
.store(in: &cell.disposeBag)
UserDefaults.shared.observe(\.customUserInterfaceStyle, options: [.initial, .new]) { [weak cell] defaults, _ in
guard let cell = cell else { return }
switch defaults.customUserInterfaceStyle {
case .unspecified: cell.update(with: .automatic)
case .dark: cell.update(with: .dark)
case .light: cell.update(with: .light)
@unknown default:
assertionFailure()
}
}
.store(in: &cell.observations)
cell.delegate = settingsAppearanceTableViewCellDelegate
return cell
case .notification(let objectID, let switchMode):

View File

@ -21,9 +21,10 @@ enum NotificationSection: Equatable, Hashable {
extension NotificationSection {
static func tableViewDiffableDataSource(
for tableView: UITableView,
dependency: NeedsDependency,
managedObjectContext: NSManagedObjectContext,
delegate: NotificationTableViewCellDelegate,
dependency: NeedsDependency
statusTableViewCellDelegate: StatusTableViewCellDelegate
) -> UITableViewDiffableDataSource<NotificationSection, NotificationItem> {
UITableViewDiffableDataSource(tableView: tableView) {
[weak delegate, weak dependency]
@ -32,137 +33,47 @@ extension NotificationSection {
switch notificationItem {
case .notification(let objectID, let attribute):
guard let notification = try? managedObjectContext.existingObject(with: objectID) as? MastodonNotification,
!notification.isDeleted else {
return UITableViewCell()
}
!notification.isDeleted
else { return UITableViewCell() }
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: NotificationStatusTableViewCell.self), for: indexPath) as! NotificationStatusTableViewCell
cell.delegate = delegate
// configure author
cell.configure(
with: AvatarConfigurableViewConfiguration(
avatarImageURL: notification.account.avatarImageURL()
)
configure(
tableView: tableView,
cell: cell,
notification: notification,
dependency: dependency,
attribute: attribute
)
cell.delegate = delegate
cell.isAccessibilityElement = true
NotificationSection.configureStatusAccessibilityLabel(cell: cell)
return cell
func createActionImage() -> UIImage? {
return UIImage(
systemName: notification.notificationType.actionImageName,
withConfiguration: UIImage.SymbolConfiguration(
pointSize: 12, weight: .semibold
)
)?
.withTintColor(.systemBackground)
.af.imageAspectScaled(toFit: CGSize(width: 14, height: 14))
}
case .notificationStatus(objectID: let objectID, attribute: let attribute):
guard let notification = try? managedObjectContext.existingObject(with: objectID) as? MastodonNotification,
!notification.isDeleted,
let status = notification.status,
let requestUserID = dependency.context.authenticationService.activeMastodonAuthenticationBox.value?.userID
else { return UITableViewCell() }
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell
cell.avatarButton.badgeImageView.backgroundColor = notification.notificationType.color
cell.avatarButton.badgeImageView.image = createActionImage()
cell.traitCollectionDidChange
.receive(on: DispatchQueue.main)
.sink { [weak cell] in
guard let cell = cell else { return }
cell.avatarButton.badgeImageView.image = createActionImage()
}
.store(in: &cell.disposeBag)
// configure author name, notification description, timestamp
let nameText = notification.account.displayNameWithFallback
let titleLabelText: String = {
switch notification.notificationType {
case .favourite: return L10n.Scene.Notification.userFavoritedYourPost(nameText)
case .follow: return L10n.Scene.Notification.userFollowedYou(nameText)
case .followRequest: return L10n.Scene.Notification.userRequestedToFollowYou(nameText)
case .mention: return L10n.Scene.Notification.userMentionedYou(nameText)
case .poll: return L10n.Scene.Notification.userYourPollHasEnded(nameText)
case .reblog: return L10n.Scene.Notification.userRebloggedYourPost(nameText)
default: return ""
}
}()
do {
let nameContent = MastodonContent(content: nameText, emojis: notification.account.emojiMeta)
let nameMetaContent = try MastodonMetaContent.convert(document: nameContent)
let mastodonContent = MastodonContent(content: titleLabelText, emojis: notification.account.emojiMeta)
let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
cell.titleLabel.configure(content: metaContent)
if let nameRange = metaContent.string.range(of: nameMetaContent.string) {
let nsRange = NSRange(nameRange, in: metaContent.string)
cell.titleLabel.textStorage.addAttributes([
.font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold), maximumPointSize: 20),
.foregroundColor: Asset.Colors.brandBlue.color,
], range: nsRange)
}
} catch {
let metaContent = PlaintextMetaContent(string: titleLabelText)
cell.titleLabel.configure(content: metaContent)
}
let createAt = notification.createAt
cell.timestampLabel.text = createAt.localizedSlowedTimeAgoSinceNow
AppContext.shared.timestampUpdatePublisher
.receive(on: DispatchQueue.main)
.sink { [weak cell] _ in
guard let cell = cell else { return }
cell.timestampLabel.text = createAt.localizedSlowedTimeAgoSinceNow
}
.store(in: &cell.disposeBag)
// configure follow request (if exist)
if case .followRequest = notification.notificationType {
cell.acceptButton.publisher(for: .touchUpInside)
.sink { [weak cell] _ in
guard let cell = cell else { return }
cell.delegate?.notificationTableViewCell(cell, notification: notification, acceptButtonDidPressed: cell.acceptButton)
}
.store(in: &cell.disposeBag)
cell.rejectButton.publisher(for: .touchUpInside)
.sink { [weak cell] _ in
guard let cell = cell else { return }
cell.delegate?.notificationTableViewCell(cell, notification: notification, rejectButtonDidPressed: cell.rejectButton)
}
.store(in: &cell.disposeBag)
cell.buttonStackView.isHidden = false
} else {
cell.buttonStackView.isHidden = true
}
// configure status (if exist)
if let status = notification.status {
let frame = CGRect(
x: 0,
y: 0,
width: tableView.readableContentGuide.layoutFrame.width - NotificationStatusTableViewCell.statusPadding.left - NotificationStatusTableViewCell.statusPadding.right,
height: tableView.readableContentGuide.layoutFrame.height
)
StatusSection.configure(
cell: cell,
tableView: tableView,
timelineContext: .notifications,
dependency: dependency,
readableLayoutFrame: frame,
status: status,
requestUserID: notification.userID,
statusItemAttribute: attribute
)
cell.statusContainerView.isHidden = false
cell.containerStackView.alignment = .top
cell.containerStackViewBottomLayoutConstraint.constant = 0
} else {
if case .followRequest = notification.notificationType {
cell.containerStackView.alignment = .top
} else {
cell.containerStackView.alignment = .center
}
cell.statusContainerView.isHidden = true
cell.containerStackViewBottomLayoutConstraint.constant = 5 // 5pt margin when no status view
}
// configure cell
StatusSection.configureStatusTableViewCell(
cell: cell,
tableView: tableView,
timelineContext: .notifications,
dependency: dependency,
readableLayoutFrame: tableView.readableContentGuide.layoutFrame,
status: status,
requestUserID: requestUserID,
statusItemAttribute: attribute
)
cell.statusView.headerContainerView.isHidden = true // set header hide
cell.statusView.actionToolbarContainer.isHidden = true // set toolbar hide
cell.statusView.actionToolbarPlaceholderPaddingView.isHidden = false
cell.delegate = statusTableViewCellDelegate
cell.isAccessibilityElement = true
StatusSection.configureStatusAccessibilityLabel(cell: cell)
return cell
case .bottomLoader:
@ -174,3 +85,162 @@ extension NotificationSection {
}
}
extension NotificationSection {
static func configure(
tableView: UITableView,
cell: NotificationStatusTableViewCell,
notification: MastodonNotification,
dependency: NeedsDependency,
attribute: Item.StatusAttribute
) {
// configure author
cell.configure(
with: AvatarConfigurableViewConfiguration(
avatarImageURL: notification.account.avatarImageURL()
)
)
func createActionImage() -> UIImage? {
return UIImage(
systemName: notification.notificationType.actionImageName,
withConfiguration: UIImage.SymbolConfiguration(
pointSize: 12, weight: .semibold
)
)?
.withTintColor(.systemBackground)
.af.imageAspectScaled(toFit: CGSize(width: 14, height: 14))
}
cell.avatarButton.badgeImageView.backgroundColor = notification.notificationType.color
cell.avatarButton.badgeImageView.image = createActionImage()
cell.traitCollectionDidChange
.receive(on: DispatchQueue.main)
.sink { [weak cell] in
guard let cell = cell else { return }
cell.avatarButton.badgeImageView.image = createActionImage()
}
.store(in: &cell.disposeBag)
// configure author name, notification description, timestamp
let nameText = notification.account.displayNameWithFallback
let titleLabelText: String = {
switch notification.notificationType {
case .favourite: return L10n.Scene.Notification.userFavoritedYourPost(nameText)
case .follow: return L10n.Scene.Notification.userFollowedYou(nameText)
case .followRequest: return L10n.Scene.Notification.userRequestedToFollowYou(nameText)
case .mention: return L10n.Scene.Notification.userMentionedYou(nameText)
case .poll: return L10n.Scene.Notification.userYourPollHasEnded(nameText)
case .reblog: return L10n.Scene.Notification.userRebloggedYourPost(nameText)
default: return ""
}
}()
do {
let nameContent = MastodonContent(content: nameText, emojis: notification.account.emojiMeta)
let nameMetaContent = try MastodonMetaContent.convert(document: nameContent)
let mastodonContent = MastodonContent(content: titleLabelText, emojis: notification.account.emojiMeta)
let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
cell.titleLabel.configure(content: metaContent)
if let nameRange = metaContent.string.range(of: nameMetaContent.string) {
let nsRange = NSRange(nameRange, in: metaContent.string)
cell.titleLabel.textStorage.addAttributes([
.font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold), maximumPointSize: 20),
.foregroundColor: Asset.Colors.brandBlue.color,
], range: nsRange)
}
} catch {
let metaContent = PlaintextMetaContent(string: titleLabelText)
cell.titleLabel.configure(content: metaContent)
}
let createAt = notification.createAt
cell.timestampLabel.text = createAt.localizedSlowedTimeAgoSinceNow
AppContext.shared.timestampUpdatePublisher
.receive(on: DispatchQueue.main)
.sink { [weak cell] _ in
guard let cell = cell else { return }
cell.timestampLabel.text = createAt.localizedSlowedTimeAgoSinceNow
}
.store(in: &cell.disposeBag)
// configure follow request (if exist)
if case .followRequest = notification.notificationType {
cell.acceptButton.publisher(for: .touchUpInside)
.sink { [weak cell] _ in
guard let cell = cell else { return }
cell.delegate?.notificationTableViewCell(cell, notification: notification, acceptButtonDidPressed: cell.acceptButton)
}
.store(in: &cell.disposeBag)
cell.rejectButton.publisher(for: .touchUpInside)
.sink { [weak cell] _ in
guard let cell = cell else { return }
cell.delegate?.notificationTableViewCell(cell, notification: notification, rejectButtonDidPressed: cell.rejectButton)
}
.store(in: &cell.disposeBag)
cell.buttonStackView.isHidden = false
} else {
cell.buttonStackView.isHidden = true
}
// configure status (if exist)
if let status = notification.status {
let frame = CGRect(
x: 0,
y: 0,
width: tableView.readableContentGuide.layoutFrame.width - NotificationStatusTableViewCell.statusPadding.left - NotificationStatusTableViewCell.statusPadding.right,
height: tableView.readableContentGuide.layoutFrame.height
)
StatusSection.configure(
cell: cell,
tableView: tableView,
timelineContext: .notifications,
dependency: dependency,
readableLayoutFrame: frame,
status: status,
requestUserID: notification.userID,
statusItemAttribute: attribute
)
cell.statusContainerView.isHidden = false
cell.containerStackView.alignment = .top
cell.containerStackViewBottomLayoutConstraint.constant = 0
} else {
if case .followRequest = notification.notificationType {
cell.containerStackView.alignment = .top
} else {
cell.containerStackView.alignment = .center
}
cell.statusContainerView.isHidden = true
cell.containerStackViewBottomLayoutConstraint.constant = 5 // 5pt margin when no status view
}
}
static func configureStatusAccessibilityLabel(cell: NotificationStatusTableViewCell) {
// FIXME:
cell.accessibilityLabel = {
var accessibilityViews: [UIView?] = []
accessibilityViews.append(contentsOf: [
cell.titleLabel,
cell.timestampLabel,
cell.statusView
])
if !cell.statusContainerView.isHidden {
if !cell.statusView.headerContainerView.isHidden {
accessibilityViews.append(cell.statusView.headerInfoLabel)
}
accessibilityViews.append(contentsOf: [
cell.statusView.nameMetaLabel,
cell.statusView.dateLabel,
cell.statusView.contentMetaText.textView,
])
}
return accessibilityViews
.compactMap { $0?.accessibilityLabel }
.joined(separator: " ")
}()
}
}

View File

@ -37,6 +37,15 @@ extension PollSection {
managedObjectContext.performAndWait {
let option = managedObjectContext.object(with: objectID) as! PollOption
PollSection.configure(cell: cell, pollOption: option, pollItemAttribute: attribute)
cell.isAccessibilityElement = true
cell.accessibilityLabel = {
var labels: [String] = [option.title]
if let percentage = cell.pollOptionView.optionPercentageLabel.text {
labels.append(percentage)
}
return labels.joined(separator: ",")
}()
}
return cell
}

View File

@ -67,7 +67,6 @@ extension StatusSection {
timelineContext: TimelineContext,
dependency: NeedsDependency,
managedObjectContext: NSManagedObjectContext,
timestampUpdatePublisher: AnyPublisher<Date, Never>,
statusTableViewCellDelegate: StatusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate?,
threadReplyLoaderTableViewCellDelegate: ThreadReplyLoaderTableViewCellDelegate?
@ -159,6 +158,11 @@ extension StatusSection {
accessibilityElements.append(cell.statusView.avatarView)
accessibilityElements.append(cell.statusView.nameMetaLabel)
accessibilityElements.append(cell.statusView.dateLabel)
// poll
accessibilityElements.append(cell.statusView.pollTableView)
accessibilityElements.append(cell.statusView.pollVoteCountLabel)
accessibilityElements.append(cell.statusView.pollCountdownLabel)
accessibilityElements.append(cell.statusView.pollVoteButton)
// TODO: a11y
accessibilityElements.append(cell.statusView.contentMetaText.textView)
accessibilityElements.append(contentsOf: cell.statusView.statusMosaicImageViewContainer.imageViews)
@ -363,7 +367,6 @@ extension StatusSection {
}
}()
if status.author.id == requestUserID || status.reblog?.author.id == requestUserID {
// do not filter myself
} else {
@ -391,7 +394,7 @@ extension StatusSection {
// set timestamp
let createdAt = (status.reblog ?? status).createdAt
cell.statusView.dateLabel.text = createdAt.localizedSlowedTimeAgoSinceNow
cell.statusView.dateLabel.accessibilityValue = createdAt.timeAgoSinceNow
cell.statusView.dateLabel.accessibilityLabel = createdAt.timeAgoSinceNow
AppContext.shared.timestampUpdatePublisher
.receive(on: RunLoop.main) // will be paused when scrolling (on purpose)
.sink { [weak cell] _ in
@ -473,9 +476,10 @@ extension StatusSection {
.receive(on: RunLoop.main)
.sink { _ in
// do nothing
} receiveValue: { [weak cell, weak tableView] change in
} receiveValue: { [weak cell, weak tableView, weak dependency] change in
guard let cell = cell else { return }
guard let tableView = tableView else { return }
guard let dependency = dependency else { return }
guard case .update(let object) = change.changeType,
let status = object as? Status, !status.isDeleted else {
return
@ -640,7 +644,7 @@ extension StatusSection {
) {
if status.reblog != nil {
cell.statusView.headerContainerView.isHidden = false
cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage)
cell.statusView.headerIconLabel.configure(attributedString: StatusView.iconAttributedString(image: StatusView.reblogIconImage))
let headerText: String = {
let author = status.author
let name = author.displayName.isEmpty ? author.username : author.displayName
@ -658,7 +662,7 @@ extension StatusSection {
cell.statusView.headerInfoLabel.isAccessibilityElement = true
} else if status.inReplyToID != nil {
cell.statusView.headerContainerView.isHidden = false
cell.statusView.headerIconLabel.attributedText = StatusView.iconAttributedString(image: StatusView.replyIconImage)
cell.statusView.headerIconLabel.configure(attributedString: StatusView.iconAttributedString(image: StatusView.replyIconImage))
let headerText: String = {
guard let replyTo = status.replyTo else {
return L10n.Common.Controls.Status.userRepliedTo("-")
@ -721,6 +725,15 @@ extension StatusSection {
statusItemAttribute: Item.StatusAttribute
) {
// set content
let paragraphStyle = cell.statusView.contentMetaText.paragraphStyle
if let language = (status.reblog ?? status).language {
let direction = Locale.characterDirection(forLanguage: language)
paragraphStyle.alignment = direction == .rightToLeft ? .right : .left
} else {
paragraphStyle.alignment = .natural
}
cell.statusView.contentMetaText.paragraphStyle = paragraphStyle
if let content = content {
cell.statusView.contentMetaText.configure(content: content)
cell.statusView.contentMetaText.textView.accessibilityLabel = content.trimmed
@ -970,6 +983,7 @@ extension StatusSection {
cell.statusView.pollCountdownLabel.text = "-"
}
cell.statusView.isUserInteractionEnabled = !poll.expired // make voice over touch passthroughable
cell.statusView.pollTableView.allowsSelection = !poll.expired
let votedOptions = poll.options.filter { option in
@ -1072,7 +1086,7 @@ extension StatusSection {
cell.statusView.actionToolbarContainer.reblogButton.isEnabled = false
}
}
// set like
let isLike = status.favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false
let favoriteCountTitle: String = {
@ -1107,7 +1121,7 @@ extension StatusSection {
StatusSection.setupStatusMoreButtonMenu(cell: cell, dependency: dependency, status: status)
})
.store(in: &cell.disposeBag)
self.setupStatusMoreButtonMenu(cell: cell, dependency: dependency, status: status)
setupStatusMoreButtonMenu(cell: cell, dependency: dependency, status: status)
}
static func configureStatusAccessibilityLabel(cell: StatusTableViewCell) {

View File

@ -0,0 +1,64 @@
//
// UserSection.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-11-1.
//
import os.log
import UIKit
import CoreData
import CoreDataStack
import MetaTextKit
import MastodonMeta
enum UserSection: Hashable {
case main
}
extension UserSection {
static let logger = Logger(subsystem: "StatusSection", category: "logic")
static func tableViewDiffableDataSource(
for tableView: UITableView,
dependency: NeedsDependency,
managedObjectContext: NSManagedObjectContext
) -> UITableViewDiffableDataSource<UserSection, UserItem> {
UITableViewDiffableDataSource(tableView: tableView) { [
weak dependency
] tableView, indexPath, item -> UITableViewCell? in
guard let dependency = dependency else { return UITableViewCell() }
switch item {
case .follower(let objectID),
.following(let objectID):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UserTableViewCell.self), for: indexPath) as! UserTableViewCell
managedObjectContext.performAndWait {
let user = managedObjectContext.object(with: objectID) as! MastodonUser
configure(cell: cell, user: user)
}
return cell
case .bottomLoader:
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell
cell.startAnimating()
return cell
case .bottomHeader(let text):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineFooterTableViewCell.self), for: indexPath) as! TimelineFooterTableViewCell
cell.messageLabel.text = text
return cell
} // end switch
} // end UITableViewDiffableDataSource
} // end static func tableViewDiffableDataSource { }
}
extension UserSection {
static func configure(
cell: UserTableViewCell,
user: MastodonUser
) {
cell.configure(user: user)
}
}

View File

@ -0,0 +1,25 @@
//
// Instance.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-10-9.
//
import UIKit
import CoreDataStack
import MastodonSDK
extension Instance {
var configuration: Mastodon.Entity.Instance.Configuration? {
guard let configurationRaw = configurationRaw else { return nil }
guard let configuration = try? JSONDecoder().decode(Mastodon.Entity.Instance.Configuration.self, from: configurationRaw) else {
return nil
}
return configuration
}
static func encode(configuration: Mastodon.Entity.Instance.Configuration) -> Data? {
return try? JSONEncoder().encode(configuration)
}
}

View File

@ -11,9 +11,9 @@ import MastodonSDK
extension Setting {
var appearance: SettingsItem.AppearanceMode {
return SettingsItem.AppearanceMode(rawValue: appearanceRaw) ?? .automatic
}
// var appearance: SettingsItem.AppearanceMode {
// return SettingsItem.AppearanceMode(rawValue: appearanceRaw) ?? .automatic
// }
var activeSubscription: Subscription? {
return (subscriptions ?? Set())

View File

@ -20,6 +20,10 @@ extension MetaLabel {
case titleView
case settingTableFooter
case autoCompletion
case accountListName
case accountListUsername
case sidebarHeadline(isSelected: Bool)
case sidebarSubheadline(isSelected: Bool)
}
convenience init(style: Style) {
@ -30,41 +34,45 @@ extension MetaLabel {
textContainer.lineBreakMode = .byTruncatingTail
textContainer.lineFragmentPadding = 0
setup(style: style)
}
func setup(style: Style) {
let font: UIFont
let textColor: UIColor
switch style {
case .statusHeader:
font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .medium), maximumPointSize: 17)
textColor = Asset.Colors.Label.secondary.color
case .statusName:
font = .systemFont(ofSize: 17, weight: .semibold)
textColor = Asset.Colors.Label.primary.color
case .notificationTitle:
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20)
textColor = Asset.Colors.Label.secondary.color
case .profileFieldName:
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 20)
textColor = Asset.Colors.Label.primary.color
case .profileFieldValue:
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 20)
textColor = Asset.Colors.Label.primary.color
textAlignment = .right
case .titleView:
font = .systemFont(ofSize: 17, weight: .semibold)
textColor = Asset.Colors.Label.primary.color
textAlignment = .center
paragraphStyle.alignment = .center
case .recommendAccountName:
font = .systemFont(ofSize: 18, weight: .semibold)
textColor = .white
case .settingTableFooter:
font = .preferredFont(forTextStyle: .footnote)
textColor = Asset.Colors.Label.secondary.color
@ -74,8 +82,20 @@ extension MetaLabel {
case .autoCompletion:
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 22)
textColor = Asset.Colors.brandBlue.color
case .accountListName:
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular), maximumPointSize: 22)
textColor = Asset.Colors.Label.primary.color
case .accountListUsername:
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20)
textColor = Asset.Colors.Label.secondary.color
case .sidebarHeadline(let isSelected):
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 22, weight: .regular), maximumPointSize: 20)
textColor = isSelected ? .white : Asset.Colors.Label.primary.color
case .sidebarSubheadline(let isSelected):
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 13, weight: .regular), maximumPointSize: 18)
textColor = isSelected ? .white : Asset.Colors.Label.secondary.color
}
self.font = font
self.textColor = textColor
@ -91,6 +111,24 @@ extension MetaLabel {
}
extension MetaLabel {
func configure(attributedString: NSAttributedString) {
let attributedString = NSMutableAttributedString(attributedString: attributedString)
MetaText.setAttributes(
for: attributedString,
textAttributes: textAttributes,
linkAttributes: linkAttributes,
paragraphStyle: paragraphStyle,
content: PlaintextMetaContent(string: "")
)
textStorage.setAttributedString(attributedString)
self.attributedText = attributedString
setNeedsDisplay()
}
}
struct PlaintextMetaContent: MetaContent {
let string: String
let entities: [Meta.Entity] = []

View File

@ -1,24 +0,0 @@
//
// NSDiffableDataSourceSnapshot.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-6-19.
//
import UIKit
//extension NSDiffableDataSourceSnapshot {
// func itemIdentifier(for indexPath: IndexPath) -> ItemIdentifierType? {
// guard 0..<numberOfSections ~= indexPath.section else {
// return nil
// }
//
// let items = itemIdentifiers(inSection: sectionIdentifiers[indexPath.section])
//
// guard 0..<items.endIndex ~= indexPath.item else {
// return nil
// }
//
// return items[indexPath.item]
// }
//}

View File

@ -0,0 +1,40 @@
//
// UICollectionViewDiffableDataSource.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-10-11.
//
import UIKit
// ref: https://www.jessesquires.com/blog/2021/07/08/diffable-data-source-behavior-changes-and-reconfiguring-cells-in-ios-15/
extension UICollectionViewDiffableDataSource {
func reloadData(
snapshot: NSDiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType>,
completion: (() -> Void)? = nil
) {
if #available(iOS 15.0, *) {
self.applySnapshotUsingReloadData(snapshot, completion: completion)
} else {
self.apply(snapshot, animatingDifferences: false, completion: completion)
}
}
func applySnapshot(
_ snapshot: NSDiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType>,
animated: Bool,
completion: (() -> Void)? = nil) {
if #available(iOS 15.0, *) {
self.apply(snapshot, animatingDifferences: animated, completion: completion)
} else {
if animated {
self.apply(snapshot, animatingDifferences: true, completion: completion)
} else {
UIView.performWithoutAnimation {
self.apply(snapshot, animatingDifferences: true, completion: completion)
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More