Merge branch 'main' into candidate

This commit is contained in:
xmflsct 2022-12-24 02:25:48 +01:00
commit b447bf43ed
184 changed files with 14775 additions and 15948 deletions

11
.gitignore vendored
View File

@ -66,4 +66,13 @@ buck-out/
web-build/
dist/
# @end expo-cli
# @end expo-cli
# yarn 3
.pnp.*
.yarn/*
!.yarn/patches
# !.yarn/plugins
# !.yarn/releases
!.yarn/sdks
!.yarn/versions

View File

@ -1,7 +1,7 @@
diff --git a/node_modules/@types/react-native-share-menu/index.d.ts b/node_modules/@types/react-native-share-menu/index.d.ts
index f52822c..ee98565 100755
--- a/node_modules/@types/react-native-share-menu/index.d.ts
+++ b/node_modules/@types/react-native-share-menu/index.d.ts
diff --git a/index.d.ts b/index.d.ts
index f52822c8bed928f387baf90fdb7342c7416a775a..6d9d480d18342832c4b07af2b10f4a63ff538e7b 100755
--- a/index.d.ts
+++ b/index.d.ts
@@ -5,11 +5,9 @@
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 3.7
@ -17,12 +17,18 @@ index f52822c..ee98565 100755
export type ShareCallback = (share?: ShareData) => void;
@@ -28,7 +26,7 @@ interface ShareMenuReactView {
dismissExtension(error?: string): void;
openApp(): void;
continueInApp(extraData?: object): void;
@@ -25,10 +23,10 @@ interface ShareMenu {
}
interface ShareMenuReactView {
- dismissExtension(error?: string): void;
- openApp(): void;
- continueInApp(extraData?: object): void;
- data(): Promise<{mimeType: string, data: string}>;
+ data(): Promise<{data: {mimeType: string; data: string}[]}>;
+ dismissExtension(error?: string): void
+ openApp(): void
+ continueInApp(extraData?: object): void
+ data(): Promise<{ data: { mimeType: string; data: string }[] }>
}
export const ShareMenuReactView: ShareMenuReactView;

View File

@ -0,0 +1,13 @@
diff --git a/ios/EXAV/EXAudioSessionManager.m b/ios/EXAV/EXAudioSessionManager.m
index 81dce13366c3947b12c863f7b39c0237882a6c36..fa27e0a354d48a994ca46e19642a5e224d42d9a8 100644
--- a/ios/EXAV/EXAudioSessionManager.m
+++ b/ios/EXAV/EXAudioSessionManager.m
@@ -170,7 +170,7 @@ - (void)moduleDidBackground:(id)backgroundingModule
[_foregroundedModules compact];
// Any possible failures are silent
- [self _updateSessionConfiguration];
+ // [self _updateSessionConfiguration];
}
- (void)moduleDidForeground:(id)module

View File

@ -1,7 +1,7 @@
diff --git a/node_modules/react-native-fast-image/RNFastImage.podspec b/node_modules/react-native-fast-image/RNFastImage.podspec
index db0fada..b23cd91 100644
--- a/node_modules/react-native-fast-image/RNFastImage.podspec
+++ b/node_modules/react-native-fast-image/RNFastImage.podspec
diff --git a/RNFastImage.podspec b/RNFastImage.podspec
index db0fada63fc06191f8620d336d244edde6c3dba3..b23cd91a9d70bdb8abd2f4ba1417c2c35e5a1d4c 100644
--- a/RNFastImage.podspec
+++ b/RNFastImage.podspec
@@ -16,6 +16,6 @@ Pod::Spec.new do |s|
s.source_files = "ios/**/*.{h,m}"
@ -11,10 +11,10 @@ index db0fada..b23cd91 100644
+ s.dependency 'SDWebImage', '~> 5.14.2'
+ s.dependency 'SDWebImageWebPCoder', '~> 0.9.1'
end
diff --git a/node_modules/react-native-fast-image/android/build.gradle b/node_modules/react-native-fast-image/android/build.gradle
index 5b21cd5..19d82f8 100644
--- a/node_modules/react-native-fast-image/android/build.gradle
+++ b/node_modules/react-native-fast-image/android/build.gradle
diff --git a/android/build.gradle b/android/build.gradle
index 5b21cd59c40a5754f5d19c77e2a0eb0229925911..19d82f826e88125c5e6d87ee7c348fac621f548c 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -65,4 +65,5 @@ dependencies {
implementation "com.github.bumptech.glide:glide:${glideVersion}"
implementation "com.github.bumptech.glide:okhttp3-integration:${glideVersion}"

View File

@ -1,7 +1,7 @@
diff --git a/node_modules/react-native-htmlview/HTMLView.js b/node_modules/react-native-htmlview/HTMLView.js
index 43f8b7e..728112b 100644
--- a/node_modules/react-native-htmlview/HTMLView.js
+++ b/node_modules/react-native-htmlview/HTMLView.js
diff --git a/HTMLView.js b/HTMLView.js
index 43f8b7eb552d9a44b5feef74ec2ae7d7ddbc2fca..334d144f1fb96067726bca199ff37267c2fa0fb2 100644
--- a/HTMLView.js
+++ b/HTMLView.js
@@ -1,7 +1,7 @@
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
@ -16,7 +16,7 @@ index 43f8b7e..728112b 100644
RootComponent: PropTypes.func,
rootComponentProps: PropTypes.object,
- style: ViewPropTypes.style,
+ style: PropTypes.any,
+ style: PropTypes.object,
stylesheet: PropTypes.object,
TextComponent: PropTypes.func,
textComponentProps: PropTypes.object,

View File

@ -1,7 +1,7 @@
diff --git a/node_modules/react-native-share-menu/android/build.gradle b/node_modules/react-native-share-menu/android/build.gradle
index 9557fdb..ebdeb6f 100644
--- a/node_modules/react-native-share-menu/android/build.gradle
+++ b/node_modules/react-native-share-menu/android/build.gradle
diff --git a/android/build.gradle b/android/build.gradle
index 9557fdbf2fbf97b7f7aeaf7ce86d301a8ced213d..ebdeb6f4de7846d3241101001755595c52a4b05e 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,12 +1,12 @@
apply plugin: 'com.android.library'
@ -19,10 +19,10 @@ index 9557fdb..ebdeb6f 100644
versionCode 1
versionName "1.0"
ndk {
diff --git a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
index f42bce6..ee36062 100644
--- a/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
+++ b/node_modules/react-native-share-menu/ios/ReactShareViewController.swift
diff --git a/ios/ReactShareViewController.swift b/ios/ReactShareViewController.swift
index f42bce6ce7e3f48a7ddc83f3366b68fd0664b1a0..ee360622b1d03cc9661c78c6f210b84c3b19a725 100644
--- a/ios/ReactShareViewController.swift
+++ b/ios/ReactShareViewController.swift
@@ -13,7 +13,7 @@ class ReactShareViewController: ShareViewController, RCTBridgeDelegate, ReactSha
func sourceURL(for bridge: RCTBridge!) -> URL! {
#if DEBUG
@ -32,10 +32,10 @@ index f42bce6..ee36062 100644
#else
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
diff --git a/node_modules/react-native-share-menu/ios/ShareViewController.swift b/node_modules/react-native-share-menu/ios/ShareViewController.swift
index 12d8c92..64aa72b 100644
--- a/node_modules/react-native-share-menu/ios/ShareViewController.swift
+++ b/node_modules/react-native-share-menu/ios/ShareViewController.swift
diff --git a/ios/ShareViewController.swift b/ios/ShareViewController.swift
index 12d8c92dda20fabd9e7b55fec57b3d867414063c..8a1db0de285b18a9358a10b2ca8293a8c7d56a8e 100644
--- a/ios/ShareViewController.swift
+++ b/ios/ShareViewController.swift
@@ -19,8 +19,8 @@ class ShareViewController: SLComposeServiceViewController {
var hostAppUrlScheme: String?
var sharedItems: [Any] = []
@ -78,7 +78,7 @@ index 12d8c92..64aa72b 100644
override func configurationItems() -> [Any]! {
// To add configuration options via table cells at the bottom of the sheet, return an array of SLComposeSheetConfigurationItem here.
return []
@@ -238,11 +235,10 @@ class ShareViewController: SLComposeServiceViewController {
@@ -238,7 +235,7 @@ class ShareViewController: SLComposeServiceViewController {
func completeRequest() {
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super's -didSelectPost, which will similarly complete the extension context.
@ -87,7 +87,3 @@ index 12d8c92..64aa72b 100644
}
func cancelRequest() {
extensionContext!.cancelRequest(withError: NSError())
}
-
}

7
.yarnrc.yml Normal file
View File

@ -0,0 +1,7 @@
nodeLinker: node-modules
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
spec: "@yarnpkg/plugin-typescript"
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"

View File

@ -1,47 +1,30 @@
module.exports = function (api) {
api.cache(true)
api.cache(false)
const plugins = [
'@babel/plugin-proposal-optional-chaining',
[
'module-resolver',
{
root: ['./'],
alias: {
'@assets': './assets',
'@root': './src',
'@api': './src/api',
'@helpers': './src/helpers',
'@components': './src/components',
'@screens': './src/screens',
'@utils': './src/utils'
}
}
],
'react-native-reanimated/plugin'
]
if (
process.env.NODE_ENV === 'production' ||
process.env.BABEL_ENV === 'production'
) {
if (process.env.NODE_ENV === 'production' || process.env.BABEL_ENV === 'production') {
plugins.push('transform-remove-console')
}
return {
presets: [
'babel-preset-expo',
presets: ['babel-preset-expo'],
plugins: [
'@babel/plugin-proposal-optional-chaining',
[
'@babel/preset-react',
'module-resolver',
{
importSource: '@welldone-software/why-did-you-render',
runtime: 'automatic',
development:
process.env.NODE_ENV === 'development' ||
process.env.BABEL_ENV === 'development'
root: ['./'],
alias: {
'@assets': './assets',
'@root': './src',
'@api': './src/api',
'@helpers': './src/helpers',
'@components': './src/components',
'@screens': './src/screens',
'@utils': './src/utils'
}
}
]
],
plugins
],
'react-native-reanimated/plugin'
]
}
}

View File

@ -1,3 +1,3 @@
Enjoy toooting! This version includes following improvements and fixes:
- Fixed wrongly update notification
- Fix some random crashes
- Allowing adding more context of reports
- Option to disable autoplay gif

View File

@ -1,3 +1,3 @@
toooting愉快此版本包括以下改进和修复
- 修复错误的升级通知
- 修复部分应用崩溃
- 可添加举报细节
- 新增暂停自动播放gif动画选项

View File

@ -16,7 +16,7 @@ PODS:
- ExpoModulesCore
- EXNotifications (0.17.0):
- ExpoModulesCore
- Expo (47.0.8):
- Expo (47.0.9):
- ExpoModulesCore
- ExpoCrypto (12.0.0):
- ExpoModulesCore
@ -26,7 +26,7 @@ PODS:
- ExpoModulesCore
- ExpoLocalization (14.0.0):
- ExpoModulesCore
- ExpoModulesCore (1.0.3):
- ExpoModulesCore (1.0.4):
- React-Core
- ReactCommon/turbomodule/core
- ExpoRandom (13.0.0):
@ -297,7 +297,7 @@ PODS:
- React-Core
- react-native-cameraroll (5.2.0):
- React-Core
- react-native-image-picker (4.10.2):
- react-native-image-picker (4.10.3):
- React-Core
- react-native-ios-context-menu (1.15.1):
- React-Core
@ -694,12 +694,12 @@ SPEC CHECKSUMS:
EXFileSystem: 60602b6eefa6873f97172c684b7537c9760b50d6
EXFont: 319606bfe48c33b5b5063fb0994afdc496befe80
EXNotifications: babce2a87b7922051354fcfe7a74dd279b7e272a
Expo: 36b5f625d36728adbdd1934d4d57182f319ab832
Expo: 5523a4835730104a301caeac1e68dad095a9dfff
ExpoCrypto: 51e7662c7f5bfeab25b7909b8a5d545ec15d4877
ExpoHaptics: 5a56d30a87ea213dd00b09566dc4b441a4dff97f
ExpoKeepAwake: 69b59d0a8d2b24de9f82759c39b3821fec030318
ExpoLocalization: e202d1e2a4950df17ac8d0889d65a1ffd7532d7e
ExpoModulesCore: b5d21c8880afda6fb6ee95469f9ac2ec9b98e995
ExpoModulesCore: 8211c89bcc3ba86e2d02c54b1d31f1fa81acb6de
ExpoRandom: 58b7e0a5fe1adf1cb6dc1cbe503a6fe9524f36ce
ExpoStoreReview: ff6d631f2949eb7e4b2d14146ef6af25a16d770d
ExpoWebBrowser: 073e50f16669d498fb49063b9b7fe780b24f7fda
@ -732,7 +732,7 @@ SPEC CHECKSUMS:
react-native-blur: 50c9feabacbc5f49b61337ebc32192c6be7ec3c3
react-native-blurhash: add4df9a937b4e021a24bc67a0714f13e0bd40b7
react-native-cameraroll: 0ff04cc4e0ff5f19a94ff4313e5c8bc4503cd86d
react-native-image-picker: bf34f3f516d139ed3e24c5f5a381a91819e349ea
react-native-image-picker: 60f4246eb5bb7187fc15638a8c1f13abd3820695
react-native-ios-context-menu: b170594b4448c0cd10c79e13432216bac99de1ac
react-native-language-detection: f414937fa715108ab50a6269a3de0bcb95e4ceb0
react-native-menu: 8e172cfcf0e42e92f028e7781eddf84d430cae24

View File

@ -1,6 +1,6 @@
{
"name": "tooot",
"version": "4.7.2",
"version": "4.8.0",
"description": "tooot for Mastodon",
"author": "xmflsct <me@xmflsct.com>",
"license": "GPL-3.0-or-later",
@ -14,8 +14,7 @@
"iphone": "react-native run-ios --simulator 'iPhone 14 Pro'",
"ipad": "react-native run-ios --simulator 'iPad Pro (11-inch) (4th generation)'",
"app:build": "bundle exec fastlane",
"clean": "react-native-clean-project",
"postinstall": "patch-package"
"clean": "react-native-clean-project"
},
"dependencies": {
"@expo/react-native-action-sheet": "^4.0.1",
@ -34,24 +33,24 @@
"@react-native-community/netinfo": "9.3.7",
"@react-native-community/segmented-control": "^2.2.2",
"@react-native-menu/menu": "^0.7.2",
"@react-navigation/bottom-tabs": "^6.5.1",
"@react-navigation/bottom-tabs": "^6.5.2",
"@react-navigation/native": "^6.1.1",
"@react-navigation/native-stack": "^6.9.6",
"@react-navigation/stack": "^6.3.9",
"@react-navigation/native-stack": "^6.9.7",
"@react-navigation/stack": "^6.3.10",
"@reduxjs/toolkit": "^1.9.1",
"@sentry/react-native": "4.12.0",
"@sharcoux/slider": "^6.1.1",
"@tanstack/react-query": "^4.20.4",
"axios": "^1.2.1",
"diff": "^5.1.0",
"expo": "^47.0.8",
"expo-auth-session": "^3.7.3",
"expo": "^47.0.9",
"expo-auth-session": "^3.8.0",
"expo-av": "^13.0.2",
"expo-constants": "^14.0.2",
"expo-crypto": "^12.0.0",
"expo-file-system": "^15.1.1",
"expo-haptics": "^12.0.1",
"expo-linking": "^3.2.3",
"expo-linking": "^3.3.0",
"expo-localization": "^14.0.0",
"expo-notifications": "^0.17.0",
"expo-random": "^13.0.0",
@ -61,14 +60,14 @@
"expo-store-review": "^6.0.0",
"expo-video-thumbnails": "^7.0.0",
"expo-web-browser": "~12.0.0",
"i18next": "^22.4.5",
"i18next": "^22.4.6",
"linkify-it": "^4.0.1",
"lodash": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^12.1.1",
"react-intl": "^6.2.5",
"react-native": "0.70.6",
"react-native": "^0.70.6",
"react-native-animated-spinkit": "^1.5.2",
"react-native-base64": "^0.2.1",
"react-native-blurhash": "^1.1.10",
@ -77,7 +76,7 @@
"react-native-flash-message": "^0.3.1",
"react-native-gesture-handler": "~2.8.0",
"react-native-htmlview": "^0.16.0",
"react-native-image-picker": "^4.10.2",
"react-native-image-picker": "^4.10.3",
"react-native-ios-context-menu": "^1.15.1",
"react-native-language-detection": "^0.2.2",
"react-native-pager-view": "^6.1.2",
@ -94,33 +93,35 @@
"rn-placeholder": "^3.0.3",
"rtl-detect": "^1.0.4",
"valid-url": "^1.0.9",
"zeego": "^0.5.0"
"zeego": "^1.0.2"
},
"devDependencies": {
"@babel/core": "^7.20.5",
"@babel/plugin-proposal-optional-chaining": "^7.18.9",
"@babel/preset-react": "^7.18.6",
"@babel/core": "^7.20.7",
"@babel/plugin-proposal-optional-chaining": "^7.20.7",
"@babel/preset-typescript": "^7.18.6",
"@expo/config": "^7.0.3",
"@types/diff": "^5.0.2",
"@types/linkify-it": "^3.0.2",
"@types/lodash": "^4.14.191",
"@types/react": "~18.0.26",
"@types/react-dom": "~18.0.9",
"@types/react-native": "~0.70.8",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.10",
"@types/react-native": "^0.70.8",
"@types/react-native-base64": "^0.2.0",
"@types/react-native-share-menu": "^5.0.2",
"@types/react-timeago": "^4.1.3",
"@types/valid-url": "^1.0.3",
"@welldone-software/why-did-you-render": "^7.0.1",
"babel-plugin-module-resolver": "^4.1.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"chalk": "^4.1.2",
"dotenv": "^16.0.3",
"expo-cli": "^6.0.8",
"patch-package": "^6.5.0",
"postinstall-postinstall": "^2.1.0",
"react-native-clean-project": "^4.0.1",
"typescript": "^4.9.4"
},
"packageManager": "yarn@3.3.1",
"resolutions": {
"react-native-fast-image@^8.6.3": "patch:react-native-fast-image@npm%3A8.6.3#./.yarn/patches/react-native-fast-image-npm-8.6.3-03ee2d23c0.patch",
"expo-av@^13.0.2": "patch:expo-av@npm%3A13.0.2#./.yarn/patches/expo-av-npm-13.0.2-7a651776f1.patch",
"react-native-htmlview@^0.16.0": "patch:react-native-htmlview@npm%3A0.16.0#./.yarn/patches/react-native-htmlview-npm-0.16.0-501f1b89ba.patch",
"react-native-share-menu@^6.0.0": "patch:react-native-share-menu@npm%3A6.0.0#./.yarn/patches/react-native-share-menu-npm-6.0.0-f1094c3204.patch",
"@types/react-native-share-menu@^5.0.2": "patch:@types/react-native-share-menu@npm%3A5.0.2#./.yarn/patches/@types-react-native-share-menu-npm-5.0.2-373df17ecc.patch"
}
}

View File

@ -1,14 +0,0 @@
diff --git a/node_modules/expo-av/ios/EXAV/EXAudioSessionManager.m b/node_modules/expo-av/ios/EXAV/EXAudioSessionManager.m
index 81dce13..8664b90 100644
--- a/node_modules/expo-av/ios/EXAV/EXAudioSessionManager.m
+++ b/node_modules/expo-av/ios/EXAV/EXAudioSessionManager.m
@@ -168,9 +168,6 @@ - (void)moduleDidBackground:(id)backgroundingModule
// compact doesn't work, that's why we need the `|| !pointer` above
// http://www.openradar.me/15396578
[_foregroundedModules compact];
-
- // Any possible failures are silent
- [self _updateSessionConfiguration];
}
- (void)moduleDidForeground:(id)module

View File

@ -1,8 +1,46 @@
import 'i18next'
import common from '../i18n/en/common.json'
import screens from '../i18n/en/screens.json'
import screenAccountSelection from '../i18n/en/screens/accountSelection.json'
import screenActions from '../i18n/en/screens/actions.json'
import screenAnnouncements from '../i18n/en/screens/announcements.json'
import screenCompose from '../i18n/en/screens/compose.json'
import screenImageViewer from '../i18n/en/screens/imageViewer.json'
import screenTabs from '../i18n/en/screens/tabs.json'
import componentContextMenu from '../i18n/en/components/contextMenu.json'
import componentEmojis from '../i18n/en/components/emojis.json'
import componentInstance from '../i18n/en/components/instance.json'
import componentMediaSelector from '../i18n/en/components/mediaSelector.json'
import componentParse from '../i18n/en/components/parse.json'
import componentRelationship from '../i18n/en/components/relationship.json'
import componentTimeline from '../i18n/en/components/timeline.json'
declare module 'i18next' {
interface CustomTypeOptions {
defaultNS: 'common',
defaultNS: 'common'
resources: {
common: typeof common
screens: typeof screens
screenAccountSelection: typeof screenAccountSelection
screenActions: typeof screenActions
screenAnnouncements: typeof screenAnnouncements
screenCompose: typeof screenCompose
screenImageViewer: typeof screenImageViewer
screenTabs: typeof screenTabs
componentContextMenu: typeof componentContextMenu
componentEmojis: typeof componentEmojis
componentInstance: typeof componentInstance
componentMediaSelector: typeof componentMediaSelector
componentParse: typeof componentParse
componentRelationship: typeof componentRelationship
componentTimeline: typeof componentTimeline
}
returnNull: false
returnEmptyString: false
}
}

View File

@ -470,6 +470,11 @@ declare namespace Mastodon {
updated_at: string
}
type Rule = {
id: string
text: string
}
type Status = {
// Base
id: string

View File

@ -4,7 +4,6 @@ import queryClient from '@helpers/queryClient'
import i18n from '@root/i18n/i18n'
import Screens from '@root/Screens'
import audio from '@root/startup/audio'
import dev from '@root/startup/dev'
import log from '@root/startup/log'
import netInfo from '@root/startup/netInfo'
import push from '@root/startup/push'
@ -31,7 +30,6 @@ Platform.select({
android: LogBox.ignoreLogs(['Setting a timer for a long period of time'])
})
dev()
sentry()
audio()
push()

View File

@ -9,7 +9,6 @@ import ScreenAnnouncements from '@screens/Announcements'
import ScreenCompose from '@screens/Compose'
import ScreenImagesViewer from '@screens/ImagesViewer'
import ScreenTabs from '@screens/Tabs'
import * as Sentry from '@sentry/react-native'
import initQuery from '@utils/initQuery'
import { RootStackParamList } from '@utils/navigation/navigators'
import pushUseConnect from '@utils/push/useConnect'
@ -25,11 +24,12 @@ import { useTheme } from '@utils/styles/ThemeManager'
import { themes } from '@utils/styles/themes'
import * as Linking from 'expo-linking'
import { addScreenshotListener } from 'expo-screen-capture'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import React, { useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Alert, Platform, StatusBar } from 'react-native'
import ShareMenu from 'react-native-share-menu'
import { useSelector } from 'react-redux'
import { routingInstrumentation } from './startup/sentry'
import { useAppDispatch } from './store'
const Stack = createNativeStackNavigator<RootStackParamList>()
@ -39,13 +39,16 @@ export interface Props {
}
const Screens: React.FC<Props> = ({ localCorrupt }) => {
const { t } = useTranslation('screens')
const { t } = useTranslation([
'common',
'screens',
'screenAnnouncements',
'screenAccountSelection'
])
const dispatch = useAppDispatch()
const instanceActive = useSelector(getInstanceActive)
const { colors, theme } = useTheme()
const routeRef = useRef<{ name?: string; params?: {} }>()
// Push hooks
const instances = useSelector(getInstances, (prev, next) => prev.length === next.length)
pushUseConnect()
@ -55,7 +58,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
// Prevent screenshot alert
useEffect(() => {
const screenshotListener = addScreenshotListener(() =>
Alert.alert(t('screenshot.title'), t('screenshot.message'), [
Alert.alert(t('screens:screenshot.title'), t('screens:screenshot.message'), [
{ text: t('common:buttons.confirm'), style: 'destructive' }
])
)
@ -68,7 +71,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
const showLocalCorrect = () => {
if (localCorrupt) {
displayMessage({
message: t('localCorrupt.message'),
message: t('screens:localCorrupt.message'),
description: localCorrupt.length ? localCorrupt : undefined,
type: 'danger'
})
@ -92,15 +95,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
}, [instanceActive])
// Callbacks
const navigationContainerOnReady = useCallback(() => {
const currentRoute = navigationRef.getCurrentRoute()
routeRef.current = {
name: currentRoute?.name,
params: currentRoute?.params ? JSON.stringify(currentRoute.params) : undefined
}
}, [])
const navigationContainerOnStateChange = useCallback(() => {
const previousRoute = routeRef.current
const currentRoute = navigationRef.getCurrentRoute()
const matchTabName = currentRoute?.name?.match(/(Tab-.*)-Root/)
@ -108,15 +103,6 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
//@ts-ignore
dispatch(updatePreviousTab(matchTabName[1]))
}
if (previousRoute?.name !== currentRoute?.name) {
Sentry.setContext('page', {
previous: previousRoute,
current: currentRoute
})
}
routeRef.current = currentRoute
}, [])
// Deep linking for compose
@ -176,7 +162,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
if (!typesImage.includes(mime.split('/')[1])) {
console.warn('Image type not supported:', mime.split('/')[1])
displayMessage({
message: t('shareError.imageNotSupported', {
message: t('screens:shareError.imageNotSupported', {
type: mime.split('/')[1]
}),
type: 'danger'
@ -188,7 +174,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
if (!typesVideo.includes(mime.split('/')[1])) {
console.warn('Video type not supported:', mime.split('/')[1])
displayMessage({
message: t('shareError.videoNotSupported', {
message: t('screens:shareError.videoNotSupported', {
type: mime.split('/')[1]
}),
type: 'danger'
@ -274,7 +260,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
<NavigationContainer
ref={navigationRef}
theme={themes[theme]}
onReady={navigationContainerOnReady}
onReady={() => routingInstrumentation.registerNavigationContainer(navigationRef)}
onStateChange={navigationContainerOnStateChange}
>
<Stack.Navigator initialRouteName='Screen-Tabs'>
@ -345,4 +331,4 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
)
}
export default React.memo(Screens, () => true)
export default Screens

View File

@ -11,7 +11,7 @@ import Icon from './Icon'
import CustomText from './Text'
export interface Props {
account: Mastodon.Account
account: Partial<Mastodon.Account> & Pick<Mastodon.Account, 'id' | 'acct' | 'username'>
props?: PressableProps
}
@ -42,11 +42,11 @@ const ComponentAccount: React.FC<PropsWithChildren & Props> = ({ account, props,
style={{
width: StyleConstants.Avatar.S,
height: StyleConstants.Avatar.S,
borderRadius: 6,
borderRadius: 8,
marginRight: StyleConstants.Spacing.S
}}
/>
<View>
<View style={{ flex: 1 }}>
<CustomText numberOfLines={1}>
<ParseEmojis
content={account.display_name || account.username}

View File

@ -7,7 +7,6 @@ import { chunk, forEach, groupBy, sortBy } from 'lodash'
import React, { createRef, PropsWithChildren, useEffect, useReducer, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Keyboard, KeyboardAvoidingView, View } from 'react-native'
import FastImage from 'react-native-fast-image'
import { Edge, SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'
import { useSelector } from 'react-redux'
import EmojisContext, { Emojis, emojisReducer, EmojisState } from './Emojis/helpers/EmojisContext'
@ -35,7 +34,7 @@ const ComponentEmojis: React.FC<Props & PropsWithChildren> = ({
emojisDispatch({ type: 'input', payload: inputProps })
}, [inputProps])
const { t } = useTranslation()
const { t } = useTranslation(['componentEmojis'])
const { data } = useEmojisQuery({})
const frequentEmojis = useSelector(getInstanceFrequentEmojis, () => true)
useEffect(() => {

View File

@ -25,10 +25,10 @@ import EmojisContext from './helpers/EmojisContext'
const EmojisList = () => {
const dispatch = useAppDispatch()
const { reduceMotionEnabled } = useAccessibility()
const { t } = useTranslation()
const { t } = useTranslation(['common', 'screenCompose'])
const { emojisState, emojisDispatch } = useContext(EmojisContext)
const { colors, mode } = useTheme()
const { colors } = useTheme()
const addEmoji = (shortcode: string) => {
if (emojisState.targetIndex === -1) {
@ -158,7 +158,6 @@ const EmojisList = () => {
onChangeText={setSearch}
autoCapitalize='none'
clearButtonMode='always'
keyboardAppearance={mode}
autoCorrect={false}
spellCheck={false}
/>

View File

@ -18,6 +18,7 @@ export interface Props {
loading?: boolean
disabled?: boolean
destructive?: boolean
onPress: () => void
}
@ -34,6 +35,7 @@ const HeaderRight: React.FC<Props> = ({
background = false,
loading,
disabled,
destructive = false,
onPress
}) => {
const { colors, theme } = useTheme()
@ -41,10 +43,7 @@ const HeaderRight: React.FC<Props> = ({
const loadingSpinkit = useMemo(
() => (
<View style={{ position: 'absolute' }}>
<Flow
size={StyleConstants.Font.Size.M * 1.25}
color={colors.secondary}
/>
<Flow size={StyleConstants.Font.Size.M * 1.25} color={colors.secondary} />
</View>
),
[theme]
@ -59,7 +58,7 @@ const HeaderRight: React.FC<Props> = ({
name={content}
style={{ opacity: loading ? 0 : 1 }}
size={StyleConstants.Spacing.M * 1.25}
color={disabled ? colors.secondary : colors.primaryDefault}
color={disabled ? colors.secondary : destructive ? colors.red : colors.primaryDefault}
/>
{loading && loadingSpinkit}
</>
@ -69,8 +68,13 @@ const HeaderRight: React.FC<Props> = ({
<>
<CustomText
fontStyle='M'
fontWeight={destructive ? 'Bold' : 'Normal'}
style={{
color: disabled ? colors.secondary : colors.primaryDefault,
color: disabled
? colors.secondary
: destructive
? colors.red
: colors.primaryDefault,
opacity: loading ? 0 : 1
}}
children={content}
@ -94,14 +98,10 @@ const HeaderRight: React.FC<Props> = ({
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: background
? colors.backgroundOverlayDefault
: undefined,
backgroundColor: background ? colors.backgroundOverlayDefault : undefined,
minHeight: 44,
minWidth: 44,
marginRight: native
? -StyleConstants.Spacing.S
: StyleConstants.Spacing.S,
marginRight: native ? -StyleConstants.Spacing.S : StyleConstants.Spacing.S,
...(type === 'icon' && {
borderRadius: 100
}),

View File

@ -85,7 +85,6 @@ const ComponentInput = forwardRef(
multiline,
numberOfLines: Platform.OS === 'android' ? 5 : undefined
})}
keyboardAppearance={mode}
textAlignVertical='top'
{...props}
/>

View File

@ -12,55 +12,44 @@ export interface Props {
potentialWidth?: number
}
const InstanceInfo = React.memo(
({ style, header, content, potentialWidth }: Props) => {
const { colors } = useTheme()
const InstanceInfo: React.FC<Props> = ({ style, header, content, potentialWidth }) => {
const { colors } = useTheme()
return (
<View
style={[
{
flex: 1,
marginTop: StyleConstants.Spacing.M,
paddingLeft: StyleConstants.Spacing.Global.PagePadding,
paddingRight: StyleConstants.Spacing.Global.PagePadding
},
style
]}
accessible
>
<CustomText
fontStyle='S'
style={{
marginBottom: StyleConstants.Spacing.XS,
color: colors.primaryDefault
}}
fontWeight='Bold'
children={header}
return (
<View
style={[
{
flex: 1,
marginTop: StyleConstants.Spacing.M,
paddingLeft: StyleConstants.Spacing.Global.PagePadding,
paddingRight: StyleConstants.Spacing.Global.PagePadding
},
style
]}
accessible
>
<CustomText
fontStyle='S'
style={{
marginBottom: StyleConstants.Spacing.XS,
color: colors.primaryDefault
}}
fontWeight='Bold'
children={header}
/>
{content ? (
<CustomText fontStyle='M' style={{ color: colors.primaryDefault }} children={content} />
) : (
<PlaceholderLine
width={potentialWidth ? potentialWidth * StyleConstants.Font.Size.M : undefined}
height={StyleConstants.Font.LineHeight.M}
color={colors.shimmerDefault}
noMargin
style={{ borderRadius: 0 }}
/>
{content ? (
<CustomText
fontStyle='M'
style={{ color: colors.primaryDefault }}
children={content}
/>
) : (
<PlaceholderLine
width={
potentialWidth
? potentialWidth * StyleConstants.Font.Size.M
: undefined
}
height={StyleConstants.Font.LineHeight.M}
color={colors.shimmerDefault}
noMargin
style={{ borderRadius: 0 }}
/>
)}
</View>
)
},
(prev, next) => prev.content === next.content
)
)}
</View>
)
}
export default InstanceInfo

View File

@ -35,7 +35,7 @@ const ComponentInstance: React.FC<Props> = ({
disableHeaderImage,
goBack = false
}) => {
const { t } = useTranslation('componentInstance')
const { t } = useTranslation(['common', 'componentInstance'])
const { colors, mode } = useTheme()
const navigation = useNavigation<TabMeStackNavigationProp<'Tab-Me-Root' | 'Tab-Me-Switch'>>()
@ -113,16 +113,20 @@ const ComponentInstance: React.FC<Props> = ({
const processUpdate = useCallback(() => {
if (domain) {
if (instances && instances.filter(instance => instance.url === domain).length) {
Alert.alert(t('update.alert.title'), t('update.alert.message'), [
{
text: t('common:buttons.cancel'),
style: 'cancel'
},
{
text: t('common:buttons.continue'),
onPress: () => appsMutation.mutate({ domain })
}
])
Alert.alert(
t('componentInstance:update.alert.title'),
t('componentInstance:update.alert.message'),
[
{
text: t('common:buttons.cancel'),
style: 'cancel'
},
{
text: t('common:buttons.continue'),
onPress: () => appsMutation.mutate({ domain })
}
]
)
} else {
appsMutation.mutate({ domain })
}
@ -209,7 +213,7 @@ const ComponentInstance: React.FC<Props> = ({
processUpdate()
}
}}
placeholder={' ' + t('server.textInput.placeholder')}
placeholder={' ' + t('componentInstance:server.textInput.placeholder')}
placeholderTextColor={colors.secondary}
returnKeyType='go'
keyboardAppearance={mode}
@ -222,7 +226,7 @@ const ComponentInstance: React.FC<Props> = ({
/>
<Button
type='text'
content={t('server.button')}
content={t('componentInstance:server.button')}
onPress={processUpdate}
disabled={!instanceQuery.data?.uri && !whitelisted}
loading={instanceQuery.isFetching || appsMutation.isLoading}
@ -239,31 +243,31 @@ const ComponentInstance: React.FC<Props> = ({
paddingTop: StyleConstants.Spacing.XS
}}
>
{t('server.whitelisted')}
{t('componentInstance:server.whitelisted')}
</CustomText>
) : (
<Placeholder>
<InstanceInfo
header={t('server.information.name')}
header={t('componentInstance:server.information.name')}
content={instanceQuery.data?.title || undefined}
potentialWidth={2}
/>
<View style={{ flex: 1, flexDirection: 'row' }}>
<InstanceInfo
style={{ alignItems: 'flex-start' }}
header={t('server.information.accounts')}
header={t('componentInstance:server.information.accounts')}
content={instanceQuery.data?.stats?.user_count?.toString() || undefined}
potentialWidth={4}
/>
<InstanceInfo
style={{ alignItems: 'center' }}
header={t('server.information.statuses')}
header={t('componentInstance:server.information.statuses')}
content={instanceQuery.data?.stats?.status_count?.toString() || undefined}
potentialWidth={4}
/>
<InstanceInfo
style={{ alignItems: 'flex-end' }}
header={t('server.information.domains')}
header={t('componentInstance:server.information.domains')}
content={instanceQuery.data?.stats?.domain_count?.toString() || undefined}
potentialWidth={4}
/>
@ -287,7 +291,7 @@ const ComponentInstance: React.FC<Props> = ({
}}
/>
<CustomText fontStyle='S' style={{ flex: 1, color: colors.secondary }}>
{t('server.disclaimer.base')}
{t('componentInstance:server.disclaimer.base')}
</CustomText>
</View>
<View
@ -312,7 +316,8 @@ const ComponentInstance: React.FC<Props> = ({
accessibilityRole='link'
>
<Trans
i18nKey='componentInstance:server.terms.base'
ns='componentInstance'
i18nKey='server.terms.base'
components={[
<CustomText
accessible

View File

@ -13,7 +13,7 @@ import validUrl from 'valid-url'
const regexEmoji = new RegExp(/(:[A-Za-z0-9_]+:)/)
export interface Props {
content: string
content?: string
emojis?: Mastodon.Emoji[]
size?: 'S' | 'M' | 'L'
adaptiveSize?: boolean
@ -23,6 +23,8 @@ export interface Props {
const ParseEmojis = React.memo(
({ content, emojis, size = 'M', adaptiveSize = false, fontBold = false, style }: Props) => {
if (!content) return null
const { reduceMotionEnabled } = useAccessibility()
const adaptiveFontsize = useSelector(getSettingsFontsize)
@ -93,7 +95,7 @@ const ParseEmojis = React.memo(
</CustomText>
)
},
(prev, next) => prev.content === next.content
(prev, next) => prev.content === next.content && prev.style?.color === next.style?.color
)
export default ParseEmojis

View File

@ -2,6 +2,7 @@ import Icon from '@components/Icon'
import openLink from '@components/openLink'
import ParseEmojis from '@components/Parse/Emojis'
import CustomText from '@components/Text'
import { getHost } from '@helpers/urlMatcher'
import { useNavigation, useRoute } from '@react-navigation/native'
import { StackNavigationProp } from '@react-navigation/stack'
import { TabLocalStackParamList } from '@utils/navigation/navigators'
@ -13,7 +14,7 @@ import { useTheme } from '@utils/styles/ThemeManager'
import { isEqual } from 'lodash'
import React, { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform, Pressable, TextStyleIOS, View } from 'react-native'
import { Pressable, TextStyleIOS, View } from 'react-native'
import HTMLView from 'react-native-htmlview'
import { useSelector } from 'react-redux'
@ -102,7 +103,7 @@ const renderNode = ({
)
}
} else {
const domain = href?.split(new RegExp(/:\/\/(.[^\/]+\/.{3})/))
const host = getHost(href)
// Need example here
const content = node.children && node.children[0] && node.children[0].data
const shouldBeTag = tags && tags.filter(tag => `#${tag.name}` === content).length > 0
@ -127,8 +128,8 @@ const renderNode = ({
}
}}
>
{content && content !== href ? content : showFullLink ? href : domain?.[1]}
{!shouldBeTag ? '...' : null}
{content && content !== href ? content : showFullLink ? href : host}
{!shouldBeTag ? '/...' : null}
</CustomText>
)
}

View File

@ -16,7 +16,7 @@ export interface Props {
const RelationshipIncoming: React.FC<Props> = ({ id }) => {
const { theme } = useTheme()
const { t } = useTranslation()
const { t } = useTranslation(['common', 'componentRelationship'])
const queryKeyRelationship: QueryKeyRelationship = ['Relationship', { id }]
const queryKeyNotification: QueryKeyTimeline = ['Timeline', { page: 'Notifications' }]
@ -33,7 +33,7 @@ const RelationshipIncoming: React.FC<Props> = ({ id }) => {
type: 'error',
theme,
message: t('common:message.error.message', {
function: t(`relationship:${type}.function`)
function: t(`componentRelationship:${type}.function` as any)
}),
...(err.status &&
typeof err.status === 'number' &&

View File

@ -22,7 +22,7 @@ export interface Props {
const RelationshipOutgoing: React.FC<Props> = ({ id }: Props) => {
const { theme } = useTheme()
const { t } = useTranslation('componentRelationship')
const { t } = useTranslation(['common', 'componentRelationship'])
const canFollowNotify = useSelector(checkInstanceFeature('account_follow_notify'))
@ -44,7 +44,7 @@ const RelationshipOutgoing: React.FC<Props> = ({ id }: Props) => {
theme,
type: 'error',
message: t('common:message.error.message', {
function: t(`${action}.function`)
function: t(`componentRelationship:${action}.function` as any)
}),
...(err.status &&
typeof err.status === 'number' &&
@ -61,15 +61,15 @@ const RelationshipOutgoing: React.FC<Props> = ({ id }: Props) => {
let onPress: () => void
if (query.isError) {
content = t('button.error')
content = t('componentRelationship:button.error')
onPress = () => {}
} else {
if (query.data?.blocked_by) {
content = t('button.blocked_by')
content = t('componentRelationship:button.blocked_by')
onPress = () => {}
} else {
if (query.data?.blocking) {
content = t('button.blocking')
content = t('componentRelationship:button.blocking')
onPress = () => {
mutation.mutate({
id,
@ -82,7 +82,7 @@ const RelationshipOutgoing: React.FC<Props> = ({ id }: Props) => {
}
} else {
if (query.data?.following) {
content = t('button.following')
content = t('componentRelationship:button.following')
onPress = () => {
mutation.mutate({
id,
@ -95,7 +95,7 @@ const RelationshipOutgoing: React.FC<Props> = ({ id }: Props) => {
}
} else {
if (query.data?.requested) {
content = t('button.requested')
content = t('componentRelationship:button.requested')
onPress = () => {
mutation.mutate({
id,
@ -107,7 +107,7 @@ const RelationshipOutgoing: React.FC<Props> = ({ id }: Props) => {
})
}
} else {
content = t('button.default')
content = t('componentRelationship:button.default')
onPress = () => {
mutation.mutate({
id,

View File

@ -11,9 +11,15 @@ export interface Props {
multiple?: boolean
options: { selected: boolean; content: string }[]
setOptions: React.Dispatch<React.SetStateAction<{ selected: boolean; content: string }[]>>
disabled?: boolean
}
const Selections: React.FC<Props> = ({ multiple = false, options, setOptions }) => {
const Selections: React.FC<Props> = ({
multiple = false,
options,
setOptions,
disabled = false
}) => {
const { colors } = useTheme()
const isSelected = (index: number): string =>
@ -22,10 +28,11 @@ const Selections: React.FC<Props> = ({ multiple = false, options, setOptions })
: `${multiple ? 'Square' : 'Circle'}`
return (
<>
<View>
{options.map((option, index) => (
<Pressable
key={index}
disabled={disabled}
style={{ flex: 1, paddingVertical: StyleConstants.Spacing.S }}
onPress={() => {
if (multiple) {
@ -56,15 +63,18 @@ const Selections: React.FC<Props> = ({ multiple = false, options, setOptions })
}}
name={isSelected(index)}
size={StyleConstants.Font.Size.M}
color={colors.primaryDefault}
color={disabled ? colors.disabled : colors.primaryDefault}
/>
<CustomText style={{ flex: 1 }}>
<ParseEmojis content={option.content} />
<ParseEmojis
content={option.content}
style={{ color: disabled ? colors.disabled : colors.primaryDefault }}
/>
</CustomText>
</View>
</Pressable>
))}
</>
</View>
)
}

View File

@ -196,37 +196,19 @@ const TimelineDefault: React.FC<Props> = ({
</ContextMenu.Trigger>
<ContextMenu.Content>
{mShare.map((mGroup, index) => (
<ContextMenu.Group key={index}>
{mGroup.map(menu => (
<ContextMenu.Item key={menu.key} {...menu.item}>
<ContextMenu.ItemTitle children={menu.title} />
<ContextMenu.ItemIcon iosIconName={menu.icon} />
</ContextMenu.Item>
{[mShare, mStatus, mInstance].map(type => (
<>
{type.map((mGroup, index) => (
<ContextMenu.Group key={index}>
{mGroup.map(menu => (
<ContextMenu.Item key={menu.key} {...menu.item}>
<ContextMenu.ItemTitle children={menu.title} />
<ContextMenu.ItemIcon ios={{ name: menu.icon }} />
</ContextMenu.Item>
))}
</ContextMenu.Group>
))}
</ContextMenu.Group>
))}
{mStatus.map((mGroup, index) => (
<ContextMenu.Group key={index}>
{mGroup.map(menu => (
<ContextMenu.Item key={menu.key} {...menu.item}>
<ContextMenu.ItemTitle children={menu.title} />
<ContextMenu.ItemIcon iosIconName={menu.icon} />
</ContextMenu.Item>
))}
</ContextMenu.Group>
))}
{mInstance.map((mGroup, index) => (
<ContextMenu.Group key={index}>
{mGroup.map(menu => (
<ContextMenu.Item key={menu.key} {...menu.item}>
<ContextMenu.ItemTitle children={menu.title} />
<ContextMenu.ItemIcon iosIconName={menu.icon} />
</ContextMenu.Item>
))}
</ContextMenu.Group>
</>
))}
</ContextMenu.Content>
</ContextMenu.Root>

View File

@ -13,74 +13,71 @@ export interface Props {
queryKey: QueryKeyTimeline
}
const TimelineEmpty = React.memo(
({ queryKey }: Props) => {
const { status, refetch } = useTimelineQuery({
...queryKey[1],
options: { notifyOnChangeProps: ['status'] }
})
const TimelineEmpty: React.FC<Props> = ({ queryKey }) => {
const { status, refetch } = useTimelineQuery({
...queryKey[1],
options: { notifyOnChangeProps: ['status'] }
})
const { colors } = useTheme()
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
const { t } = useTranslation('componentTimeline')
const children = () => {
switch (status) {
case 'loading':
return <Circle size={StyleConstants.Font.Size.L} color={colors.secondary} />
case 'error':
return (
<>
<Icon name='Frown' size={StyleConstants.Font.Size.L} color={colors.primaryDefault} />
<CustomText
fontStyle='M'
style={{
marginTop: StyleConstants.Spacing.S,
marginBottom: StyleConstants.Spacing.L,
color: colors.primaryDefault
}}
>
{t('empty.error.message')}
</CustomText>
<Button type='text' content={t('empty.error.button')} onPress={() => refetch()} />
</>
)
case 'success':
return (
<>
<Icon
name='Smartphone'
size={StyleConstants.Font.Size.L}
color={colors.primaryDefault}
/>
<CustomText
fontStyle='M'
style={{
marginTop: StyleConstants.Spacing.S,
marginBottom: StyleConstants.Spacing.L,
color: colors.secondary
}}
>
{t('empty.success.message')}
</CustomText>
</>
)
}
const children = () => {
switch (status) {
case 'loading':
return <Circle size={StyleConstants.Font.Size.L} color={colors.secondary} />
case 'error':
return (
<>
<Icon name='Frown' size={StyleConstants.Font.Size.L} color={colors.primaryDefault} />
<CustomText
fontStyle='M'
style={{
marginTop: StyleConstants.Spacing.S,
marginBottom: StyleConstants.Spacing.L,
color: colors.primaryDefault
}}
>
{t('empty.error.message')}
</CustomText>
<Button type='text' content={t('empty.error.button')} onPress={() => refetch()} />
</>
)
case 'success':
return (
<>
<Icon
name='Smartphone'
size={StyleConstants.Font.Size.L}
color={colors.primaryDefault}
/>
<CustomText
fontStyle='M'
style={{
marginTop: StyleConstants.Spacing.S,
marginBottom: StyleConstants.Spacing.L,
color: colors.secondary
}}
>
{t('empty.success.message')}
</CustomText>
</>
)
}
return (
<View
style={{
flex: 1,
minHeight: '100%',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: colors.backgroundDefault
}}
>
{children()}
</View>
)
},
() => true
)
}
return (
<View
style={{
flex: 1,
minHeight: '100%',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: colors.backgroundDefault
}}
>
{children()}
</View>
)
}
export default TimelineEmpty

View File

@ -13,49 +13,47 @@ export interface Props {
disableInfinity: boolean
}
const TimelineFooter = React.memo(
({ queryKey, disableInfinity }: Props) => {
const { hasNextPage } = useTimelineQuery({
...queryKey[1],
options: {
enabled: !disableInfinity,
notifyOnChangeProps: ['hasNextPage'],
getNextPageParam: lastPage =>
lastPage?.links?.next && {
...(lastPage.links.next.isOffset
? { offset: lastPage.links.next.id }
: { max_id: lastPage.links.next.id })
}
}
})
const TimelineFooter: React.FC<Props> = ({ queryKey, disableInfinity }) => {
const { hasNextPage } = useTimelineQuery({
...queryKey[1],
options: {
enabled: !disableInfinity,
notifyOnChangeProps: ['hasNextPage'],
getNextPageParam: lastPage =>
lastPage?.links?.next && {
...(lastPage.links.next.isOffset
? { offset: lastPage.links.next.id }
: { max_id: lastPage.links.next.id })
}
}
})
const { colors } = useTheme()
const { colors } = useTheme()
return (
<View
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
padding: StyleConstants.Spacing.M
}}
>
{!disableInfinity && hasNextPage ? (
<Circle size={StyleConstants.Font.Size.L} color={colors.secondary} />
) : (
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
<Trans
i18nKey='componentTimeline:end.message'
components={[
<Icon name='Coffee' size={StyleConstants.Font.Size.S} color={colors.secondary} />
]}
/>
</CustomText>
)}
</View>
)
},
() => true
)
return (
<View
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
padding: StyleConstants.Spacing.M
}}
>
{!disableInfinity && hasNextPage ? (
<Circle size={StyleConstants.Font.Size.L} color={colors.secondary} />
) : (
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
<Trans
ns='componentTimeline'
i18nKey='end.message'
components={[
<Icon name='Coffee' size={StyleConstants.Font.Size.S} color={colors.secondary} />
]}
/>
</CustomText>
)}
</View>
)
}
export default TimelineFooter

View File

@ -164,37 +164,19 @@ const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
</ContextMenu.Trigger>
<ContextMenu.Content>
{mShare.map((mGroup, index) => (
<ContextMenu.Group key={index}>
{mGroup.map(menu => (
<ContextMenu.Item key={menu.key} {...menu.item}>
<ContextMenu.ItemTitle children={menu.title} />
<ContextMenu.ItemIcon iosIconName={menu.icon} />
</ContextMenu.Item>
{[mShare, mStatus, mInstance].map(type => (
<>
{type.map((mGroup, index) => (
<ContextMenu.Group key={index}>
{mGroup.map(menu => (
<ContextMenu.Item key={menu.key} {...menu.item}>
<ContextMenu.ItemTitle children={menu.title} />
<ContextMenu.ItemIcon ios={{ name: menu.icon }} />
</ContextMenu.Item>
))}
</ContextMenu.Group>
))}
</ContextMenu.Group>
))}
{mStatus.map((mGroup, index) => (
<ContextMenu.Group key={index}>
{mGroup.map(menu => (
<ContextMenu.Item key={menu.key} {...menu.item}>
<ContextMenu.ItemTitle children={menu.title} />
<ContextMenu.ItemIcon iosIconName={menu.icon} />
</ContextMenu.Item>
))}
</ContextMenu.Group>
))}
{mInstance.map((mGroup, index) => (
<ContextMenu.Group key={index}>
{mGroup.map(menu => (
<ContextMenu.Item key={menu.key} {...menu.item}>
<ContextMenu.ItemTitle children={menu.title} />
<ContextMenu.ItemIcon iosIconName={menu.icon} />
</ContextMenu.Item>
))}
</ContextMenu.Group>
</>
))}
</ContextMenu.Content>
</ContextMenu.Root>

View File

@ -28,7 +28,7 @@ const TimelineActions: React.FC = () => {
if (!queryKey || !status || disableDetails) return null
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>()
const { t } = useTranslation('componentTimeline')
const { t } = useTranslation(['common', 'componentTimeline'])
const { colors, theme } = useTheme()
const iconColor = colors.secondary
@ -54,13 +54,15 @@ const TimelineActions: React.FC = () => {
queryClient.invalidateQueries(tempQueryKey)
}
},
onError: (err: any, params, oldData) => {
onError: (err: any, params) => {
const correctParam = params as MutationVarsTimelineUpdateStatusProperty
displayMessage({
theme,
type: 'error',
message: t('common:message.error.message', {
function: t(`shared.actions.${correctParam.payload.property}.function`)
function: t(
`componentTimeline:shared.actions.${correctParam.payload.property}.function` as any
)
}),
...(err.status &&
typeof err.status === 'number' &&
@ -94,10 +96,10 @@ const TimelineActions: React.FC = () => {
if (!status.reblogged) {
showActionSheetWithOptions(
{
title: t('shared.actions.reblogged.options.title'),
title: t('componentTimeline:shared.actions.reblogged.options.title'),
options: [
t('shared.actions.reblogged.options.public'),
t('shared.actions.reblogged.options.unlisted'),
t('componentTimeline:shared.actions.reblogged.options.public'),
t('componentTimeline:shared.actions.reblogged.options.unlisted'),
t('common:buttons.cancel')
],
cancelButtonIndex: 2,
@ -209,15 +211,14 @@ const TimelineActions: React.FC = () => {
)
const childrenReblog = useMemo(() => {
const color = (state: boolean) => (state ? colors.green : colors.secondary)
const disabled =
status.visibility === 'direct' || (status.visibility === 'private' && !ownAccount)
return (
<>
<Icon
name='Repeat'
color={
status.visibility === 'direct' || (status.visibility === 'private' && !ownAccount)
? colors.disabled
: color(status.reblogged)
}
color={disabled ? colors.disabled : color(status.reblogged)}
crossOut={disabled}
size={StyleConstants.Font.Size.L}
/>
{status.reblogs_count > 0 ? (
@ -269,7 +270,7 @@ const TimelineActions: React.FC = () => {
<Pressable
{...(highlighted
? {
accessibilityLabel: t('shared.actions.reply.accessibilityLabel'),
accessibilityLabel: t('componentTimeline:shared.actions.reply.accessibilityLabel'),
accessibilityRole: 'button'
}
: { accessibilityLabel: '' })}
@ -281,7 +282,9 @@ const TimelineActions: React.FC = () => {
<Pressable
{...(highlighted
? {
accessibilityLabel: t('shared.actions.reblogged.accessibilityLabel'),
accessibilityLabel: t(
'componentTimeline:shared.actions.reblogged.accessibilityLabel'
),
accessibilityRole: 'button'
}
: { accessibilityLabel: '' })}
@ -296,7 +299,9 @@ const TimelineActions: React.FC = () => {
<Pressable
{...(highlighted
? {
accessibilityLabel: t('shared.actions.favourited.accessibilityLabel'),
accessibilityLabel: t(
'componentTimeline:shared.actions.favourited.accessibilityLabel'
),
accessibilityRole: 'button'
}
: { accessibilityLabel: '' })}
@ -308,7 +313,9 @@ const TimelineActions: React.FC = () => {
<Pressable
{...(highlighted
? {
accessibilityLabel: t('shared.actions.bookmarked.accessibilityLabel'),
accessibilityLabel: t(
'componentTimeline:shared.actions.bookmarked.accessibilityLabel'
),
accessibilityRole: 'button'
}
: { accessibilityLabel: '' })}

View File

@ -8,6 +8,8 @@ import AttachmentAltText from './AltText'
import { Platform } from 'expo-modules-core'
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
import { aspectRatio } from './dimensions'
import { useSelector } from 'react-redux'
import { getSettingsAutoplayGifv } from '@utils/slices/settingsSlice'
export interface Props {
total: number
@ -25,6 +27,7 @@ const AttachmentVideo: React.FC<Props> = ({
gifv = false
}) => {
const { reduceMotionEnabled } = useAccessibility()
const autoplayGifv = useSelector(getSettingsAutoplayGifv)
const videoPlayer = useRef<Video>(null)
const [videoLoading, setVideoLoading] = useState(false)
@ -60,7 +63,7 @@ const AttachmentVideo: React.FC<Props> = ({
resizeMode={videoResizeMode}
{...(gifv
? {
shouldPlay: reduceMotionEnabled ? false : true,
shouldPlay: reduceMotionEnabled || !autoplayGifv ? false : true,
isMuted: true,
isLooping: true,
source: { uri: video.url }
@ -73,7 +76,7 @@ const AttachmentVideo: React.FC<Props> = ({
onFullscreenUpdate={event => {
if (event.fullscreenUpdate === VideoFullscreenUpdate.PLAYER_DID_DISMISS) {
Platform.OS === 'android' && setVideoResizeMode(ResizeMode.COVER)
if (gifv && !reduceMotionEnabled) {
if (gifv && !reduceMotionEnabled && autoplayGifv) {
videoPlayer.current?.playAsync()
} else {
videoPlayer.current?.pauseAsync()
@ -106,7 +109,7 @@ const AttachmentVideo: React.FC<Props> = ({
video.blurhash ? (
<Blurhash blurhash={video.blurhash} style={{ width: '100%', height: '100%' }} />
) : null
) : !gifv || (gifv && reduceMotionEnabled) ? (
) : !gifv || (gifv && (reduceMotionEnabled || !autoplayGifv)) ? (
<Button
round
overlay
@ -119,6 +122,21 @@ const AttachmentVideo: React.FC<Props> = ({
) : null}
<AttachmentAltText sensitiveShown={sensitiveShown} text={video.description} />
</Pressable>
{gifv && !autoplayGifv ? (
<Button
style={{
position: 'absolute',
left: StyleConstants.Spacing.S,
bottom: StyleConstants.Spacing.S
}}
overlay
size='S'
type='text'
content='GIF'
fontBold
onPress={() => {}}
/>
) : null}
</View>
)
}

View File

@ -5,8 +5,7 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React, { useContext } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform, StyleSheet, View } from 'react-native'
import { Path, Svg } from 'react-native-svg'
import { Platform } from 'react-native'
import { useSelector } from 'react-redux'
import { isRtlLang } from 'rtl-detect'
import StatusContext from './Context'
@ -45,7 +44,14 @@ const TimelineContent: React.FC<Props> = ({ notificationOwnToot = false, setSpoi
}
/>
{inThread ? (
<CustomText fontStyle='S' style={{ textAlign: 'center', color: colors.secondary, paddingVertical: StyleConstants.Spacing.XS }}>
<CustomText
fontStyle='S'
style={{
textAlign: 'center',
color: colors.secondary,
paddingVertical: StyleConstants.Spacing.XS
}}
>
{t('shared.content.expandHint')}
</CustomText>
) : null}

View File

@ -15,7 +15,7 @@ export interface FilteredProps {
const TimelineFiltered: React.FC<FilteredProps> = ({ filterResults }) => {
const { colors } = useTheme()
const { t } = useTranslation('componentTimeline')
const { t } = useTranslation(['common', 'componentTimeline'])
const main = () => {
if (!filterResults?.length) {
@ -23,18 +23,27 @@ const TimelineFiltered: React.FC<FilteredProps> = ({ filterResults }) => {
}
switch (typeof filterResults[0]) {
case 'string': // v1 filter
return <>{t('shared.filtered.match', { context: 'v1', phrase: filterResults[0] })}</>
return (
<>
{t('componentTimeline:shared.filtered.match', {
defaultValue: 'v1',
context: 'v1',
phrase: filterResults[0]
})}
</>
)
default:
return (
<>
{t('shared.filtered.match', {
{t('componentTimeline:shared.filtered.match', {
defaultValue: 'v2',
context: 'v2',
count: filterResults.length,
filters: filterResults.map(result => result.title).join(t('common:separator'))
})}
<CustomText
style={{ color: colors.blue }}
children={`\n${t('shared.filtered.reveal')}`}
children={`\n${t('componentTimeline:shared.filtered.reveal')}`}
/>
</>
)

View File

@ -28,6 +28,7 @@ const TimelineHeaderAndroid: React.FC = () => {
type: 'status',
openChange,
account: status.account,
...(status && { status }),
queryKey
})
const mStatus = menuStatus({ status, queryKey, rootQueryKey })
@ -52,34 +53,19 @@ const TimelineHeaderAndroid: React.FC = () => {
</DropdownMenu.Trigger>
<DropdownMenu.Content>
{mShare.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
</DropdownMenu.Item>
{[mShare, mAccount, mStatus].map(type => (
<>
{type.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon ios={{ name: menu.icon }} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
))}
</DropdownMenu.Group>
))}
{mAccount.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
))}
{mStatus.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
</>
))}
</DropdownMenu.Content>
</DropdownMenu.Root>

View File

@ -22,7 +22,7 @@ const HeaderConversation = ({ conversation }: Props) => {
if (!queryKey) return null
const { colors, theme } = useTheme()
const { t } = useTranslation('componentTimeline')
const { t } = useTranslation(['common', 'componentTimeline'])
const queryClient = useQueryClient()
const mutation = useTimelineMutation({
@ -32,7 +32,7 @@ const HeaderConversation = ({ conversation }: Props) => {
theme,
type: 'error',
message: t('common:message.error.message', {
function: t(`shared.header.conversation.delete.function`)
function: t(`componentTimeline:shared.header.conversation.delete.function`)
}),
...(err.status &&
typeof err.status === 'number' &&
@ -53,7 +53,7 @@ const HeaderConversation = ({ conversation }: Props) => {
numberOfLines={1}
style={{ ...StyleConstants.FontStyle.M, color: colors.secondary }}
>
<CustomText>{t('shared.header.conversation.withAccounts')}</CustomText>
<CustomText>{t('componentTimeline:shared.header.conversation.withAccounts')}</CustomText>
{conversation.accounts.map((account, index) => (
<CustomText key={account.id} numberOfLines={1}>
{index !== 0 ? t('common:separator') : undefined}

View File

@ -34,6 +34,7 @@ const TimelineHeaderDefault: React.FC = () => {
type: 'status',
openChange,
account: status.account,
...(status && { status }),
queryKey
})
const mStatus = menuStatus({ status, queryKey, rootQueryKey })
@ -82,37 +83,19 @@ const TimelineHeaderDefault: React.FC = () => {
</DropdownMenu.Trigger>
<DropdownMenu.Content>
{mShare.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
</DropdownMenu.Item>
{[mShare, mAccount, mStatus].map(type => (
<>
{type.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon ios={{ name: menu.icon }} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
))}
</DropdownMenu.Group>
))}
{mAccount.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
))}
{mStatus.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
</>
))}
</DropdownMenu.Content>
</DropdownMenu.Root>

View File

@ -42,6 +42,7 @@ const TimelineHeaderNotification: React.FC<Props> = ({ notification }) => {
type: 'status',
openChange,
account: status?.account,
...(status && { status }),
queryKey
})
const mStatus = menuStatus({ status, queryKey })
@ -74,7 +75,7 @@ const TimelineHeaderNotification: React.FC<Props> = ({ notification }) => {
/>
)
default:
if (status) {
if (status && Platform.OS !== 'android') {
return (
<Pressable
style={{ flex: 1, alignItems: 'center' }}
@ -89,48 +90,19 @@ const TimelineHeaderNotification: React.FC<Props> = ({ notification }) => {
</DropdownMenu.Trigger>
<DropdownMenu.Content>
{mShare.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
</DropdownMenu.Item>
{[mShare, mStatus, mAccount, mInstance].map(type => (
<>
{type.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon ios={{ name: menu.icon }} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
))}
</DropdownMenu.Group>
))}
{mAccount.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
))}
{mStatus.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
))}
{mInstance.map((mGroup, index) => (
<DropdownMenu.Group key={index}>
{mGroup.map(menu => (
<DropdownMenu.Item key={menu.key} {...menu.item}>
<DropdownMenu.ItemTitle children={menu.title} />
<DropdownMenu.ItemIcon iosIconName={menu.icon} />
</DropdownMenu.Item>
))}
</DropdownMenu.Group>
</>
))}
</DropdownMenu.Content>
</DropdownMenu.Root>
@ -187,19 +159,17 @@ const TimelineHeaderNotification: React.FC<Props> = ({ notification }) => {
</View>
</View>
{Platform.OS !== 'android' ? (
<View
style={[
{ marginLeft: StyleConstants.Spacing.M },
notification.type === 'follow' ||
notification.type === 'follow_request' ||
notification.type === 'admin.report'
? { flexShrink: 1 }
: { flex: 1 }
]}
children={actions()}
/>
) : null}
<View
style={[
{ marginLeft: StyleConstants.Spacing.M },
notification.type === 'follow' ||
notification.type === 'follow_request' ||
notification.type === 'admin.report'
? { flexShrink: 1 }
: { flex: 1 }
]}
children={actions()}
/>
</View>
)
}

View File

@ -9,31 +9,28 @@ export interface Props {
application?: Mastodon.Application
}
const HeaderSharedApplication = React.memo(
({ application }: Props) => {
const { colors } = useTheme()
const { t } = useTranslation('componentTimeline')
const HeaderSharedApplication: React.FC<Props> = ({ application }) => {
const { colors } = useTheme()
const { t } = useTranslation('componentTimeline')
return application && application.name !== 'Web' ? (
<CustomText
fontStyle='S'
accessibilityRole='link'
onPress={async () => {
application.website && (await openLink(application.website))
}}
style={{
marginLeft: StyleConstants.Spacing.S,
color: colors.secondary
}}
numberOfLines={1}
>
{t('shared.header.shared.application', {
application: application.name
})}
</CustomText>
) : null
},
() => true
)
return application && application.name !== 'Web' ? (
<CustomText
fontStyle='S'
accessibilityRole='link'
onPress={async () => {
application.website && (await openLink(application.website))
}}
style={{
marginLeft: StyleConstants.Spacing.S,
color: colors.secondary
}}
numberOfLines={1}
>
{t('shared.header.shared.application', {
application: application.name
})}
</CustomText>
) : null
}
export default HeaderSharedApplication

View File

@ -13,43 +13,34 @@ export interface Props {
highlighted?: boolean
}
const HeaderSharedCreated = React.memo(
({ created_at, edited_at, highlighted = false }: Props) => {
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
const HeaderSharedCreated: React.FC<Props> = ({ created_at, edited_at, highlighted = false }) => {
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
const actualTime = edited_at || created_at
const actualTime = edited_at || created_at
return (
<>
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
{highlighted ? (
<>
<FormattedDate
value={new Date(actualTime)}
dateStyle='medium'
timeStyle='short'
/>
</>
) : (
<RelativeTime time={actualTime} />
)}
</CustomText>
{edited_at ? (
<Icon
accessibilityLabel={t(
'shared.header.shared.edited.accessibilityLabel'
)}
name='Edit'
size={StyleConstants.Font.Size.S}
color={colors.secondary}
style={{ marginLeft: StyleConstants.Spacing.S }}
/>
) : null}
</>
)
},
(prev, next) => prev.edited_at === next.edited_at
)
return (
<>
<CustomText fontStyle='S' style={{ color: colors.secondary }}>
{highlighted ? (
<>
<FormattedDate value={new Date(actualTime)} dateStyle='medium' timeStyle='short' />
</>
) : (
<RelativeTime time={actualTime} />
)}
</CustomText>
{edited_at ? (
<Icon
accessibilityLabel={t('shared.header.shared.edited.accessibilityLabel')}
name='Edit'
size={StyleConstants.Font.Size.S}
color={colors.secondary}
style={{ marginLeft: StyleConstants.Spacing.S }}
/>
) : null}
</>
)
}
export default HeaderSharedCreated

View File

@ -3,34 +3,24 @@ import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
import React from 'react'
import { useTranslation } from 'react-i18next'
import { StyleSheet } from 'react-native'
export interface Props {
muted?: Mastodon.Status['muted']
}
const HeaderSharedMuted = React.memo(
({ muted }: Props) => {
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
const HeaderSharedMuted: React.FC<Props> = ({ muted }) => {
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
return muted ? (
<Icon
accessibilityLabel={t('shared.header.shared.muted.accessibilityLabel')}
name='VolumeX'
size={StyleConstants.Font.Size.S}
color={colors.secondary}
style={styles.visibility}
/>
) : null
},
() => true
)
const styles = StyleSheet.create({
visibility: {
marginLeft: StyleConstants.Spacing.S
}
})
return muted ? (
<Icon
accessibilityLabel={t('shared.header.shared.muted.accessibilityLabel')}
name='VolumeX'
size={StyleConstants.Font.Size.M}
color={colors.secondary}
style={{ marginLeft: StyleConstants.Spacing.S }}
/>
) : null
}
export default HeaderSharedMuted

View File

@ -9,48 +9,45 @@ export interface Props {
visibility: Mastodon.Status['visibility']
}
const HeaderSharedVisibility = React.memo(
({ visibility }: Props) => {
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
const HeaderSharedVisibility: React.FC<Props> = ({ visibility }) => {
const { t } = useTranslation('componentTimeline')
const { colors } = useTheme()
switch (visibility) {
case 'unlisted':
return (
<Icon
accessibilityLabel={t('shared.header.shared.visibility.private.accessibilityLabel')}
name='Unlock'
size={StyleConstants.Font.Size.S}
color={colors.secondary}
style={styles.visibility}
/>
)
case 'private':
return (
<Icon
accessibilityLabel={t('shared.header.shared.visibility.private.accessibilityLabel')}
name='Lock'
size={StyleConstants.Font.Size.S}
color={colors.secondary}
style={styles.visibility}
/>
)
case 'direct':
return (
<Icon
accessibilityLabel={t('shared.header.shared.visibility.direct.accessibilityLabel')}
name='Mail'
size={StyleConstants.Font.Size.S}
color={colors.secondary}
style={styles.visibility}
/>
)
default:
return null
}
},
() => true
)
switch (visibility) {
case 'unlisted':
return (
<Icon
accessibilityLabel={t('shared.header.shared.visibility.private.accessibilityLabel')}
name='Unlock'
size={StyleConstants.Font.Size.S}
color={colors.secondary}
style={styles.visibility}
/>
)
case 'private':
return (
<Icon
accessibilityLabel={t('shared.header.shared.visibility.private.accessibilityLabel')}
name='Lock'
size={StyleConstants.Font.Size.S}
color={colors.secondary}
style={styles.visibility}
/>
)
case 'direct':
return (
<Icon
accessibilityLabel={t('shared.header.shared.visibility.direct.accessibilityLabel')}
name='Mail'
size={StyleConstants.Font.Size.S}
color={colors.secondary}
style={styles.visibility}
/>
)
default:
return null
}
}
const styles = StyleSheet.create({
visibility: {

View File

@ -33,7 +33,7 @@ const TimelinePoll: React.FC = () => {
const poll = status.poll
const { colors, theme } = useTheme()
const { t } = useTranslation('componentTimeline')
const { t } = useTranslation(['common', 'componentTimeline'])
const [allOptions, setAllOptions] = useState(new Array(status.poll.options.length).fill(false))
@ -58,8 +58,7 @@ const TimelinePoll: React.FC = () => {
theme,
type: 'error',
message: t('common:message.error.message', {
// @ts-ignore
function: t(`shared.poll.meta.button.${theParams.payload.type}`)
function: t(`componentTimeline:shared.poll.meta.button.${theParams.payload.type}` as any)
}),
...(err.status &&
typeof err.status === 'number' &&
@ -95,7 +94,7 @@ const TimelinePoll: React.FC = () => {
})
}
type='text'
content={t('shared.poll.meta.button.vote')}
content={t('componentTimeline:shared.poll.meta.button.vote')}
loading={mutation.isLoading}
disabled={allOptions.filter(o => o !== false).length === 0}
/>
@ -120,7 +119,7 @@ const TimelinePoll: React.FC = () => {
})
}
type='text'
content={t('shared.poll.meta.button.refresh')}
content={t('componentTimeline:shared.poll.meta.button.refresh')}
loading={mutation.isLoading}
/>
</View>
@ -233,20 +232,25 @@ const TimelinePoll: React.FC = () => {
const pollVoteCounts = () => {
if (poll.voters_count !== null) {
return t('shared.poll.meta.count.voters', { count: poll.voters_count }) + ' • '
return (
t('componentTimeline:shared.poll.meta.count.voters', { count: poll.voters_count }) + ' • '
)
} else if (poll.votes_count !== null) {
return t('shared.poll.meta.count.votes', { count: poll.votes_count }) + ' • '
return (
t('componentTimeline:shared.poll.meta.count.votes', { count: poll.votes_count }) + ' • '
)
}
}
const pollExpiration = () => {
if (poll.expired) {
return t('shared.poll.meta.expiration.expired')
return t('componentTimeline:shared.poll.meta.expiration.expired')
} else {
if (poll.expires_at) {
return (
<Trans
i18nKey='componentTimeline:shared.poll.meta.expiration.until'
ns='componentTimeline'
i18nKey='shared.poll.meta.expiration.until'
components={[<RelativeTime time={poll.expires_at} />]}
/>
)

View File

@ -16,7 +16,7 @@ const TimelineTranslate = () => {
const { status, highlighted, rawContent, detectedLanguage } = useContext(StatusContext)
if (!status || !highlighted || !rawContent?.current.length) return null
const { t } = useTranslation('componentTimeline')
const { t } = useTranslation(['componentTimeline'])
const { colors } = useTheme()
const [detected, setDetected] = useState<{
@ -101,15 +101,15 @@ const TimelineTranslate = () => {
}}
>
{isError
? t('shared.translate.failed')
? t('componentTimeline:shared.translate.failed')
: isSuccess
? typeof data?.error === 'string'
? t(`shared.translate.${data.error}`)
: t('shared.translate.succeed', {
? t(`componentTimeline:shared.translate.${data.error}` as any)
: t('componentTimeline:shared.translate.succeed', {
provider: data?.provider,
source: data?.sourceLanguage
})
: t('shared.translate.default')}
: t('componentTimeline:shared.translate.default')}
</CustomText>
{isFetching ? (
<Circle

View File

@ -24,12 +24,14 @@ const menuAccount = ({
type,
openChange,
account,
status,
queryKey,
rootQueryKey
}: {
type: 'status' | 'account' // Where the action is coming from
openChange: boolean
account?: Pick<Mastodon.Account, 'id' | 'username'>
account?: Partial<Mastodon.Account> & Pick<Mastodon.Account, 'id' | 'username' | 'acct'>
status?: Mastodon.Status
queryKey?: QueryKeyTimeline
rootQueryKey?: QueryKeyTimeline
}): ContextMenu[][] => {
@ -37,7 +39,7 @@ const menuAccount = ({
const navigation =
useNavigation<NativeStackNavigationProp<TabSharedStackParamList, any, undefined>>()
const { t } = useTranslation('componentContextMenu')
const { t } = useTranslation(['common', 'componentContextMenu', 'componentRelationship'])
const menus: ContextMenu[][] = [[]]
@ -60,11 +62,15 @@ const menuAccount = ({
displayMessage({
type: 'success',
message: t('common:message.success.message', {
function: t(`account.${theParams.payload.property}.action`, {
...(theParams.payload.property !== 'reports' && {
context: (theParams.payload.currentValue || false).toString()
})
})
function: t(
`componentContextMenu:account.${theParams.payload.property}.action`,
theParams.payload.property !== 'reports'
? {
defaultValue: 'false',
context: (theParams.payload.currentValue || false).toString()
}
: { defaultValue: 'false' }
)
})
})
},
@ -73,11 +79,15 @@ const menuAccount = ({
displayMessage({
type: 'danger',
message: t('common:message.error.message', {
function: t(`account.${theParams.payload.property}.action`, {
...(theParams.payload.property !== 'reports' && {
context: (theParams.payload.currentValue || false).toString()
})
})
function: t(
`componentContextMenu:account.${theParams.payload.property}.action`,
theParams.payload.property !== 'reports'
? {
defaultValue: 'false',
context: (theParams.payload.currentValue || false).toString()
}
: { defaultValue: 'false' }
)
}),
...(err.status &&
typeof err.status === 'number' &&
@ -107,7 +117,7 @@ const menuAccount = ({
displayMessage({
type: 'danger',
message: t('common:message.error.message', {
function: t(`${action}.function`)
function: t(`componentContextMenu:${action}.function` as any)
}),
...(err.status &&
typeof err.status === 'number' &&
@ -136,7 +146,8 @@ const menuAccount = ({
hidden: false
},
title: !data?.requested
? t('account.following.action', {
? t('componentContextMenu:account.following.action', {
defaultValue: 'false',
context: (data?.following || false).toString()
})
: t('componentRelationship:button.requested'),
@ -147,6 +158,7 @@ const menuAccount = ({
: 'person.badge.minus'
})
}
if (!ownAccount) {
menus[0].push({
key: 'account-list',
@ -156,9 +168,28 @@ const menuAccount = ({
destructive: false,
hidden: !isFetched || !data?.following
},
title: t('account.inLists'),
title: t('componentContextMenu:account.inLists'),
icon: 'checklist'
})
menus[0].push({
key: 'account-show-boosts',
item: {
onSelect: () =>
relationshipMutation.mutate({
id: account.id,
type: 'outgoing',
payload: { action: 'follow', state: false, reblogs: !data?.showing_reblogs }
}),
disabled: Platform.OS !== 'android' ? !data || !isFetched : false,
destructive: false,
hidden: !isFetched || !data?.following
},
title: t('componentContextMenu:account.showBoosts.action', {
defaultValue: 'false',
context: (data?.showing_reblogs || false).toString()
}),
icon: data?.showing_reblogs ? 'rectangle.on.rectangle.slash' : 'rectangle.on.rectangle'
})
menus[0].push({
key: 'account-mute',
item: {
@ -173,40 +204,44 @@ const menuAccount = ({
destructive: false,
hidden: false
},
title: t('account.mute.action', {
title: t('componentContextMenu:account.mute.action', {
defaultValue: 'false',
context: (data?.muting || false).toString()
}),
icon: data?.muting ? 'eye' : 'eye.slash'
})
}
!ownAccount &&
menus.push([
{
key: 'account-block',
item: {
onSelect: () =>
Alert.alert(t('account.block.alert.title', { username: account.username }), undefined, [
{
text: t('common:buttons.confirm'),
style: 'destructive',
onPress: () =>
timelineMutation.mutate({
type: 'updateAccountProperty',
queryKey,
id: account.id,
payload: { property: 'block', currentValue: data?.blocking }
})
},
{
text: t('common:buttons.cancel')
}
]),
Alert.alert(
t('componentContextMenu:account.block.alert.title', { username: account.username }),
undefined,
[
{
text: t('common:buttons.confirm'),
style: 'destructive',
onPress: () =>
timelineMutation.mutate({
type: 'updateAccountProperty',
queryKey,
id: account.id,
payload: { property: 'block', currentValue: data?.blocking }
})
},
{
text: t('common:buttons.cancel')
}
]
),
disabled: Platform.OS !== 'android' ? !data || !isFetched : false,
destructive: !data?.blocking,
hidden: false
},
title: t('account.block.action', {
title: t('componentContextMenu:account.block.action', {
defaultValue: 'false',
context: (data?.blocking || false).toString()
}),
icon: data?.blocking ? 'checkmark.circle' : 'xmark.circle'
@ -214,42 +249,16 @@ const menuAccount = ({
{
key: 'account-reports',
item: {
onSelect: () =>
Alert.alert(
t('account.reports.alert.title', { username: account.username }),
undefined,
[
{
text: t('common:buttons.confirm'),
style: 'destructive',
onPress: () => {
timelineMutation.mutate({
type: 'updateAccountProperty',
queryKey,
id: account.id,
payload: { property: 'reports' }
})
timelineMutation.mutate({
type: 'updateAccountProperty',
queryKey,
id: account.id,
payload: { property: 'block', currentValue: false }
})
}
},
{
text: t('common:buttons.cancel')
}
]
),
onSelect: () => navigation.navigate('Tab-Shared-Report', { account, status }),
disabled: false,
destructive: true,
hidden: false
},
title: t('account.reports.action'),
title: t('componentContextMenu:account.reports.action'),
icon: 'flag'
}
])
}
return menus
}

View File

@ -17,7 +17,7 @@ const menuInstance = ({
}): ContextMenu[][] => {
if (!status || !queryKey) return []
const { t } = useTranslation('componentContextMenu')
const { t } = useTranslation(['common', 'componentContextMenu'])
const queryClient = useQueryClient()
const mutation = useTimelineMutation({
@ -25,7 +25,7 @@ const menuInstance = ({
displayMessage({
type: 'success',
message: t('common:message.success.message', {
function: t(`instance.block.action`, { instance })
function: t(`componentContextMenu:instance.block.action`, { instance })
})
})
queryClient.invalidateQueries(queryKey)
@ -45,8 +45,8 @@ const menuInstance = ({
item: {
onSelect: () =>
Alert.alert(
t('instance.block.alert.title', { instance }),
t('instance.block.alert.message'),
t('componentContextMenu:instance.block.alert.title', { instance }),
t('componentContextMenu:instance.block.alert.message'),
[
{
text: t('common:buttons.confirm'),
@ -68,7 +68,7 @@ const menuInstance = ({
destructive: true,
hidden: false
},
title: t('instance.block.action', { instance }),
title: t('componentContextMenu:instance.block.action', { instance }),
icon: ''
}
])

View File

@ -13,7 +13,7 @@ const menuShare = (
}
| {
type: 'account'
url: string
url?: string
}
): ContextMenu[][] => {
if (params.type === 'status' && params.visibility === 'direct') return []

View File

@ -28,7 +28,7 @@ const menuStatus = ({
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList, 'Screen-Tabs'>>()
const { theme } = useTheme()
const { t } = useTranslation('componentContextMenu')
const { t } = useTranslation(['common', 'componentContextMenu'])
const queryClient = useQueryClient()
const mutation = useTimelineMutation({
@ -41,7 +41,7 @@ const menuStatus = ({
theme,
type: 'error',
message: t('common:message.error.message', {
function: t(`status.${theFunction}.action`)
function: t(`componentContextMenu:status.${theFunction}.action` as any)
}),
...(err?.status &&
typeof err.status === 'number' &&
@ -62,52 +62,54 @@ const menuStatus = ({
const canEditPost = useSelector(checkInstanceFeature('edit_post'))
if (ownAccount) {
menus.push([
{
key: 'status-edit',
item: {
onSelect: async () => {
let replyToStatus: Mastodon.Status | undefined = undefined
if (status.in_reply_to_id) {
replyToStatus = await apiInstance<Mastodon.Status>({
method: 'get',
url: `statuses/${status.in_reply_to_id}`
}).then(res => res.body)
}
apiInstance<{
id: Mastodon.Status['id']
text: NonNullable<Mastodon.Status['text']>
spoiler_text: Mastodon.Status['spoiler_text']
}>({
menus.push([
{
key: 'status-edit',
item: {
onSelect: async () => {
let replyToStatus: Mastodon.Status | undefined = undefined
if (status.in_reply_to_id) {
replyToStatus = await apiInstance<Mastodon.Status>({
method: 'get',
url: `statuses/${status.id}/source`
}).then(res => {
navigation.navigate('Screen-Compose', {
type: 'edit',
incomingStatus: {
...status,
text: res.body.text,
spoiler_text: res.body.spoiler_text
},
...(replyToStatus && { replyToStatus }),
queryKey,
rootQueryKey
})
url: `statuses/${status.in_reply_to_id}`
}).then(res => res.body)
}
apiInstance<{
id: Mastodon.Status['id']
text: NonNullable<Mastodon.Status['text']>
spoiler_text: Mastodon.Status['spoiler_text']
}>({
method: 'get',
url: `statuses/${status.id}/source`
}).then(res => {
navigation.navigate('Screen-Compose', {
type: 'edit',
incomingStatus: {
...status,
text: res.body.text,
spoiler_text: res.body.spoiler_text
},
...(replyToStatus && { replyToStatus }),
queryKey,
rootQueryKey
})
},
disabled: false,
destructive: false,
hidden: !canEditPost
})
},
title: t('status.edit.action'),
icon: 'square.and.pencil'
disabled: false,
destructive: false,
hidden: !ownAccount || !canEditPost
},
{
key: 'status-delete-edit',
item: {
onSelect: () =>
Alert.alert(t('status.deleteEdit.alert.title'), t('status.deleteEdit.alert.message'), [
title: t('componentContextMenu:status.edit.action'),
icon: 'square.and.pencil'
},
{
key: 'status-delete-edit',
item: {
onSelect: () =>
Alert.alert(
t('componentContextMenu:status.deleteEdit.alert.title'),
t('componentContextMenu:status.deleteEdit.alert.message'),
[
{
text: t('common:buttons.confirm'),
style: 'destructive',
@ -139,19 +141,23 @@ const menuStatus = ({
{
text: t('common:buttons.cancel')
}
]),
disabled: false,
destructive: true,
hidden: false
},
title: t('status.deleteEdit.action'),
icon: 'pencil.and.outline'
]
),
disabled: false,
destructive: true,
hidden: !ownAccount
},
{
key: 'status-delete',
item: {
onSelect: () =>
Alert.alert(t('status.delete.alert.title'), t('status.delete.alert.message'), [
title: t('componentContextMenu:status.deleteEdit.action'),
icon: 'pencil.and.outline'
},
{
key: 'status-delete',
item: {
onSelect: () =>
Alert.alert(
t('componentContextMenu:status.delete.alert.title'),
t('componentContextMenu:status.delete.alert.message'),
[
{
text: t('common:buttons.confirm'),
style: 'destructive',
@ -169,70 +175,72 @@ const menuStatus = ({
text: t('common:buttons.cancel'),
style: 'default'
}
]),
disabled: false,
destructive: true,
hidden: false
},
title: t('status.delete.action'),
icon: 'trash'
}
])
menus.push([
{
key: 'status-mute',
item: {
onSelect: () =>
mutation.mutate({
type: 'updateStatusProperty',
queryKey,
rootQueryKey,
id: status.id,
payload: {
property: 'muted',
currentValue: status.muted,
propertyCount: undefined,
countValue: undefined
}
}),
disabled: false,
destructive: false,
hidden: false
},
title: t('status.mute.action', {
context: (status.muted || false).toString()
}),
icon: status.muted ? 'speaker' : 'speaker.slash'
]
),
disabled: false,
destructive: true,
hidden: !ownAccount
},
{
key: 'status-pin',
item: {
onSelect: () =>
// Also note that reblogs cannot be pinned.
mutation.mutate({
type: 'updateStatusProperty',
queryKey,
rootQueryKey,
id: status.id,
payload: {
property: 'pinned',
currentValue: status.pinned,
propertyCount: undefined,
countValue: undefined
}
}),
disabled: false,
destructive: false,
hidden: status.visibility !== 'public' && status.visibility !== 'unlisted'
},
title: t('status.pin.action', {
context: (status.pinned || false).toString()
}),
icon: status.pinned ? 'pin.slash' : 'pin'
}
])
}
title: t('componentContextMenu:status.delete.action'),
icon: 'trash'
}
])
menus.push([
{
key: 'status-mute',
item: {
onSelect: () =>
mutation.mutate({
type: 'updateStatusProperty',
queryKey,
rootQueryKey,
id: status.id,
payload: {
property: 'muted',
currentValue: status.muted
}
}),
disabled: false,
destructive: false,
hidden:
!ownAccount &&
!status.mentions.filter(mention => mention.id === instanceAccount.id).length
},
title: t('componentContextMenu:status.mute.action', {
defaultValue: 'false',
context: (status.muted || false).toString()
}),
icon: status.muted ? 'speaker' : 'speaker.slash'
},
{
key: 'status-pin',
item: {
onSelect: () =>
// Also note that reblogs cannot be pinned.
mutation.mutate({
type: 'updateStatusProperty',
queryKey,
rootQueryKey,
id: status.id,
payload: {
property: 'pinned',
currentValue: status.pinned,
propertyCount: undefined,
countValue: undefined
}
}),
disabled: false,
destructive: false,
hidden: !ownAccount || (status.visibility !== 'public' && status.visibility !== 'unlisted')
},
title: t('componentContextMenu:status.pin.action', {
defaultValue: 'false',
context: (status.pinned || false).toString()
}),
icon: status.pinned ? 'pin.slash' : 'pin'
}
])
return menus
}

View File

@ -1,6 +1,13 @@
import { store } from '@root/store'
import { getInstanceUrl } from '@utils/slices/instancesSlice'
const getHost = (url: unknown): string | void => {
if (typeof url !== 'string') return undefined
const matches = url.match(/^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?([^:\/\n]+)/i)
return matches?.[1]
}
const matchStatus = (
url: string
): { id: string; style: 'default' | 'pretty'; sameInstance: boolean } | null => {
@ -53,4 +60,4 @@ const matchAccount = (
return null
}
export { matchStatus, matchAccount }
export { getHost, matchStatus, matchAccount }

View File

@ -7,6 +7,10 @@
"action_true": "Deixa de seguir l'usuari"
},
"inLists": "Gestionar usuari de llistes",
"showBoosts": {
"action_false": "Mostra els impulsos de l'usuari",
"action_true": "Oculta els impulsos de l'usuari"
},
"mute": {
"action_false": "Silencia l'usuari",
"action_true": "Deixa de silenciar l'usuari"
@ -15,13 +19,13 @@
"action_false": "Bloqueja l'usuari",
"action_true": "Deixa de bloquejar l'usuari",
"alert": {
"title": ""
"title": "Vols bloquejar a @{{username}}?"
}
},
"reports": {
"action": "Denuncia i bloqueja l'usuari",
"alert": {
"title": ""
"title": "Vols denunciar i bloquejar a @{{username}}?"
}
}
},

View File

@ -32,7 +32,7 @@
},
"update": "L'impuls ha sigut editat",
"admin.sign_up": "{{name}} s'ha unit a la instància",
"admin.report": ""
"admin.report": "{{name}} ha reportat:"
},
"actions": {
"reply": {
@ -100,7 +100,7 @@
"fullConversation": "Llegeix conversacions",
"translate": {
"default": "Tradueix",
"succeed": "Traduït per {{provider}} amb {{source}}",
"succeed": "Traduït per {{provider}} des de l'idioma {{source}}",
"failed": "Error al traduir",
"source_not_supported": "L'idioma de la publicació no està suportada",
"target_not_supported": "Aquest idioma no està suportat"

View File

@ -4,7 +4,7 @@
"published": "S'ha publicat <0 />",
"button": {
"read": "Llegit",
"unread": "Marca com a llegit"
"unread": "Marca-ho com a llegit"
}
}
}

View File

@ -2,10 +2,10 @@
"heading": {
"left": {
"alert": {
"title": "Voleu cancel·lar l'edició?",
"title": "Vols cancel·lar l'edició?",
"buttons": {
"save": "Desa l'esborrany",
"delete": "Esborra l'esborrany"
"save": "Desa'l",
"delete": "Esborra'l"
}
}
},
@ -13,9 +13,9 @@
"button": {
"default": "Publica",
"conversation": "Envia un missatge directe",
"reply": "Publica la resposta",
"deleteEdit": "Publicació",
"edit": "Publica l'edició",
"reply": "Respon",
"deleteEdit": "Torna-ho a publicar",
"edit": "Edita",
"share": "Publicació"
},
"alert": {
@ -42,8 +42,7 @@
"placeholder": "Què et passa pel cap?",
"keyboardImage": {
"exceedMaximum": {
"title": "S'ha arribat al nombre màxim d'adjunts",
"OK": "$t(common:buttons.OK)"
"title": "S'ha arribat al nombre màxim d'adjunts"
}
}
}

View File

@ -3,7 +3,7 @@
"local": {
"name": "Seguint",
"options": {
"showBoosts": "Mostra les publicacions",
"showBoosts": "Mostra els impulsos",
"showReplies": "Mostra les respostes"
}
},
@ -28,19 +28,7 @@
"filters": {
"accessibilityLabel": "Filtra",
"accessibilityHint": "Filtra els tipus de notificacions",
"title": "Mostra les notificacions",
"options": {
"follow": "$t(screenTabs:me.push.follow.heading)",
"follow_request": "Sol·licituds de seguiment",
"favourite": "$t(screenTabs:me.push.favourite.heading)",
"reblog": "$t(screenTabs:me.push.reblog.heading)",
"mention": "$t(screenTabs:me.push.mention.heading)",
"poll": "$t(screenTabs:me.push.poll.heading)",
"status": "Publicacions d'usuaris subscrits",
"update": "Edicions d'impulsos",
"admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
"admin.report": "$t(screenTabs:me.push.admin.report.heading)"
}
"title": "Mostra les notificacions"
}
},
"me": {
@ -133,7 +121,7 @@
"listDelete": {
"heading": "Esborra la llista",
"confirm": {
"title": "Vol esborrar la llista \"{{list}}\"?",
"title": "Vols esborrar la llista \"{{list}}\"?",
"message": "Aquesta acció no es pot desfer."
}
},
@ -254,13 +242,10 @@
"content_true": "Habilitat",
"content_false": "Deshabilitat"
},
"update": {
"title": "Actualitza a la última versió"
},
"logout": {
"button": "Tanca la sessió",
"alert": {
"title": "Vol tancar la sessió?",
"title": "Vols tancar la sessió?",
"message": "Després de tancar la sessió, hauràs de tornar a iniciar la sessió",
"buttons": {
"logout": "Tanca la sessió"
@ -269,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "$t(me.stacks.fontSize.name)",
"content": {
"S": "$t(me.fontSize.sizes.S)",
"M": "$t(me.fontSize.sizes.M)",
"L": "$t(me.fontSize.sizes.L)",
"XL": "$t(me.fontSize.sizes.XL)",
"XXL": "$t(me.fontSize.sizes.XXL)"
}
},
"language": {
"heading": "$t(me.stacks.language.name)"
},
"theme": {
"heading": "Aspecte",
"options": {
@ -304,9 +276,8 @@
"external": "Utilitza el navegador del sistema"
}
},
"staticEmoji": {
"heading": "Utilitza emojis estàtics",
"description": "Si l'aplicació falla freqüentment en visualitzar la llista d'emojis, pots intentar fer servir els emojis estàtics."
"autoplayGifv": {
"heading": "Reprodueix els GIF automàticament"
},
"feedback": {
"heading": "Peticions de característiques"
@ -335,9 +306,7 @@
"moved": "S'ha traslladat",
"created_at": "Es va unir el dia {{date}}",
"summary": {
"statuses_count": "{{count}} publicacions",
"following_count": "$t(shared.users.accounts.following)",
"followers_count": "$t(shared.users.accounts.followers)"
"statuses_count": "{{count}} publicacions"
},
"toots": {
"default": "Publicacions",
@ -360,6 +329,25 @@
"history": {
"name": "Edita l'historial"
},
"report": {
"name": "",
"report": "",
"forward": {
"heading": "Envia anònimament al servidor remot {{instance}}"
},
"reasons": {
"heading": "Què està passant amb aquest compte?",
"spam": "És contingut brossa",
"other": "És una altra cosa",
"violation": "Incompleix les regles del servidor"
},
"comment": {
"heading": "Vols afegir alguna altra cosa?"
},
"violatedRules": {
"heading": "Ha incomplert les regles del servidor"
}
},
"search": {
"header": {
"prefix": "Cercant",

View File

@ -7,6 +7,10 @@
"action_true": ""
},
"inLists": "",
"showBoosts": {
"action_false": "",
"action_true": ""
},
"mute": {
"action_false": "",
"action_true": ""

View File

@ -42,8 +42,7 @@
"placeholder": "",
"keyboardImage": {
"exceedMaximum": {
"title": "",
"OK": ""
"title": ""
}
}
}

View File

@ -28,19 +28,7 @@
"filters": {
"accessibilityLabel": "",
"accessibilityHint": "",
"title": "",
"options": {
"follow": "",
"follow_request": "",
"favourite": "",
"reblog": "",
"mention": "",
"poll": "",
"status": "",
"update": "",
"admin.sign_up": "",
"admin.report": ""
}
"title": ""
}
},
"me": {
@ -254,9 +242,6 @@
"content_true": "",
"content_false": ""
},
"update": {
"title": ""
},
"logout": {
"button": "",
"alert": {
@ -269,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "",
"content": {
"S": "",
"M": "",
"L": "",
"XL": "",
"XXL": ""
}
},
"language": {
"heading": ""
},
"theme": {
"heading": "",
"options": {
@ -304,9 +276,8 @@
"external": ""
}
},
"staticEmoji": {
"heading": "",
"description": ""
"autoplayGifv": {
"heading": ""
},
"feedback": {
"heading": ""
@ -335,9 +306,7 @@
"moved": "",
"created_at": "",
"summary": {
"statuses_count": "",
"following_count": "",
"followers_count": ""
"statuses_count": ""
},
"toots": {
"default": "",
@ -360,6 +329,25 @@
"history": {
"name": ""
},
"report": {
"name": "",
"report": "",
"forward": {
"heading": ""
},
"reasons": {
"heading": "",
"spam": "",
"other": "",
"violation": ""
},
"comment": {
"heading": ""
},
"violatedRules": {
"heading": ""
}
},
"search": {
"header": {
"prefix": "",

View File

@ -7,6 +7,10 @@
"action_true": "Nutzer entfolgen"
},
"inLists": "Konten in Listen verwalten",
"showBoosts": {
"action_false": "",
"action_true": ""
},
"mute": {
"action_false": "Profil stummschalten",
"action_true": "Stummschaltung des Nutzers aufheben"
@ -15,13 +19,13 @@
"action_false": "Nutzer blockieren",
"action_true": "User entblocken",
"alert": {
"title": ""
"title": "{{username}} wirklich blockieren?"
}
},
"reports": {
"action": "Nutzer melden und blockieren",
"alert": {
"title": ""
"title": "{{username}} wirklich blockieren und melden?"
}
}
},

View File

@ -42,8 +42,7 @@
"placeholder": "Was geht in dir vor",
"keyboardImage": {
"exceedMaximum": {
"title": "Maximale Anzahl von Anhängen erreicht",
"OK": "$t(common:buttons.OK)"
"title": "Maximale Anzahl von Anhängen erreicht"
}
}
}

View File

@ -28,19 +28,7 @@
"filters": {
"accessibilityLabel": "Filter",
"accessibilityHint": "Angezeigte Benachrichtigungstypen filtern",
"title": "Benachrichtigungen anzeigen",
"options": {
"follow": "$t(screenTabs:me.push.follow.heading)",
"follow_request": "Followeranfrage",
"favourite": "$t(screenTabs:me.push.favourite.heading)",
"reblog": "$t(screenTabs:me.push.reblog.heading)",
"mention": "$t(screenTabs:me.push.mention.heading)",
"poll": "$t(screenTabs:me.push.poll.heading)",
"status": "Tröt eines abonnierten Nutzers",
"update": "Boost wurde bearbeitet",
"admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
"admin.report": "$t(screenTabs:me.push.admin.report.heading)"
}
"title": "Benachrichtigungen anzeigen"
}
},
"me": {
@ -254,9 +242,6 @@
"content_true": "Aktiviert",
"content_false": "Deaktiviert"
},
"update": {
"title": "Auf neueste Version aktualisiert"
},
"logout": {
"button": "Abmelden",
"alert": {
@ -269,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "$t(me.stacks.fontSize.name)",
"content": {
"S": "$t(me.fontSize.sizes.S)",
"M": "$t(me.fontSize.sizes.M)",
"L": "$t(me.fontSize.sizes.L)",
"XL": "$t(me.fontSize.sizes.XL)",
"XXL": "$t(me.fontSize.sizes.XXL)"
}
},
"language": {
"heading": "$t(me.stacks.language.name)"
},
"theme": {
"heading": "Erscheinungsbild",
"options": {
@ -304,9 +276,8 @@
"external": "Im Systembrowser öffnen"
}
},
"staticEmoji": {
"heading": "System-Emojis verwenden",
"description": "Wenn du beim Betrachten der Emoji-Liste häufige App-Abstürze feststellst, kannst du stattdessen versuchen, statische Emoji zu verwenden."
"autoplayGifv": {
"heading": "GIFs in der Timeline automatisch abspielen"
},
"feedback": {
"heading": "Neue Funktion vorschlagen"
@ -335,9 +306,7 @@
"moved": "Benutzer umgezogen",
"created_at": "Registriert am: {{date}}",
"summary": {
"statuses_count": "{{count}} Tröts",
"following_count": "$t(shared.users.accounts.following)",
"followers_count": "$t(shared.users.accounts.followers)"
"statuses_count": "{{count}} Tröts"
},
"toots": {
"default": "Tröts",
@ -360,6 +329,25 @@
"history": {
"name": "Bearbeitungsverlauf"
},
"report": {
"name": "",
"report": "",
"forward": {
"heading": ""
},
"reasons": {
"heading": "",
"spam": "",
"other": "",
"violation": ""
},
"comment": {
"heading": ""
},
"violatedRules": {
"heading": ""
}
},
"search": {
"header": {
"prefix": "Suche",

View File

@ -7,6 +7,10 @@
"action_true": "Unfollow user"
},
"inLists": "Manage user of lists",
"showBoosts": {
"action_false": "Show user's boosts",
"action_true": "Hide users's boosts"
},
"mute": {
"action_false": "Mute user",
"action_true": "Unmute user"

View File

@ -42,8 +42,7 @@
"placeholder": "What's on your mind",
"keyboardImage": {
"exceedMaximum": {
"title": "Maximum attachments amount reached",
"OK": "$t(common:buttons.OK)"
"title": "Maximum attachments amount reached"
}
}
}

View File

@ -28,19 +28,7 @@
"filters": {
"accessibilityLabel": "Filter",
"accessibilityHint": "Filter shown notifications' types",
"title": "Show notifications",
"options": {
"follow": "$t(screenTabs:me.push.follow.heading)",
"follow_request": "Follow request",
"favourite": "$t(screenTabs:me.push.favourite.heading)",
"reblog": "$t(screenTabs:me.push.reblog.heading)",
"mention": "$t(screenTabs:me.push.mention.heading)",
"poll": "$t(screenTabs:me.push.poll.heading)",
"status": "Toot from subscribed users",
"update": "Reblog has been edited",
"admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
"admin.report": "$t(screenTabs:me.push.admin.report.heading)"
}
"title": "Show notifications"
}
},
"me": {
@ -266,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "$t(me.stacks.fontSize.name)",
"content": {
"S": "$t(me.fontSize.sizes.S)",
"M": "$t(me.fontSize.sizes.M)",
"L": "$t(me.fontSize.sizes.L)",
"XL": "$t(me.fontSize.sizes.XL)",
"XXL": "$t(me.fontSize.sizes.XXL)"
}
},
"language": {
"heading": "$t(me.stacks.language.name)"
},
"theme": {
"heading": "Appearance",
"options": {
@ -301,9 +276,8 @@
"external": "Use system browser"
}
},
"staticEmoji": {
"heading": "Use static emoji",
"description": "If you encounter frequent app crash when viewing emoji list, you can try to use static emoji instead."
"autoplayGifv": {
"heading": "Autoplay GIF in timeline"
},
"feedback": {
"heading": "Feature Requests"
@ -332,9 +306,7 @@
"moved": "User moved",
"created_at": "Joined: {{date}}",
"summary": {
"statuses_count": "{{count}} toots",
"following_count": "$t(shared.users.accounts.following)",
"followers_count": "$t(shared.users.accounts.followers)"
"statuses_count": "{{count}} toots"
},
"toots": {
"default": "Toots",
@ -357,6 +329,25 @@
"history": {
"name": "Edit History"
},
"report": {
"name": "Report {{acct}}",
"report": "Report",
"forward": {
"heading": "Anonymously forward to remote server {{instance}}"
},
"reasons": {
"heading": "What is going on with this account?",
"spam": "It is spam",
"other": "It is something else",
"violation": "It violates server rules"
},
"comment": {
"heading": "Anything else you want to add?"
},
"violatedRules": {
"heading": "Violated server rules"
}
},
"search": {
"header": {
"prefix": "Searching",

View File

@ -1,6 +1,6 @@
{
"buttons": {
"OK": "OK",
"OK": "De acuerdo",
"apply": "Aplicar",
"cancel": "Cancelar",
"discard": "Descartar",

View File

@ -7,6 +7,10 @@
"action_true": "Dejar de seguir usuario"
},
"inLists": "Administrar usuario de listas",
"showBoosts": {
"action_false": "Mostrar los impulsos del usuario",
"action_true": "Ocultar los impulsos del usuario"
},
"mute": {
"action_false": "Silenciar usuario",
"action_true": "Dejar de silenciar al usuario"
@ -15,13 +19,13 @@
"action_false": "Bloquear usuario",
"action_true": "Desbloquear usuario",
"alert": {
"title": ""
"title": "¿Quieres bloquear a @{{username}}?"
}
},
"reports": {
"action": "Reportar y bloquear usuario",
"alert": {
"title": ""
"title": "¿Quieres denunciar y bloquear a @{{username}}?"
}
}
},
@ -38,7 +42,7 @@
"block": {
"action": "Bloquear instancia {{instance}}",
"alert": {
"title": "¿Confirmar bloqueo de la instancia {{instance}}?",
"title": "¿Quieres bloquear la instancia {{instance}}?",
"message": "Puedes silenciar o bloquear a un usuario.\n\nTras bloquear una instancia, todo su contenido junto con sus seguidores se eliminarán."
}
}
@ -59,14 +63,14 @@
"delete": {
"action": "Eliminar toot",
"alert": {
"title": "¿Confirmar eliminación?",
"title": "¿Quieres eliminar?",
"message": "Todos los boosts y favoritos se eliminarán, incluidas todas las respuestas."
}
},
"deleteEdit": {
"action": "Eliminar toot y volver a publicar",
"alert": {
"title": "¿Confirmar eliminación y volver a publicar?",
"title": "¿Quieres eliminar y volver a publicar?",
"message": "Todos los boosts y favoritos se eliminarán, incluidas todas las respuestas."
}
},

View File

@ -32,7 +32,7 @@
},
"update": "El impulso ha sido editado",
"admin.sign_up": "{{name}} se unió a la instancia",
"admin.report": ""
"admin.report": "{{name}} reportó:"
},
"actions": {
"reply": {
@ -145,7 +145,7 @@
"refresh": "Actualizar"
},
"count": {
"voters_one": "{{count}} usuarios ha votado",
"voters_one": "{{count}} usuario ha votado",
"voters_other": "{{count}} usuarios han votado",
"votes_one": "{{count}} voto",
"votes_other": "{{count}} votos"

View File

@ -2,7 +2,7 @@
"heading": {
"left": {
"alert": {
"title": "¿Cancelar edición?",
"title": "¿Quieres cancelar la edición?",
"buttons": {
"save": "Guardar borrador",
"delete": "Eliminar borrador"
@ -13,9 +13,9 @@
"button": {
"default": "Toot",
"conversation": "Mensaje privado",
"reply": "Respuesta al toot",
"deleteEdit": "Toot",
"edit": "Edita el toot",
"reply": "Responde",
"deleteEdit": "Vuelve a publicar",
"edit": "Edita",
"share": "Toot"
},
"alert": {
@ -39,11 +39,10 @@
"placeholder": "Mensaje de aviso de spoiler"
},
"textInput": {
"placeholder": "Qué está pasando",
"placeholder": "¿Qué está pasando?",
"keyboardImage": {
"exceedMaximum": {
"title": "Número máximo de adjuntos alcanzado",
"OK": "$t(common:buttons.OK)"
"title": "Número máximo de adjuntos alcanzado"
}
}
}

View File

@ -11,7 +11,7 @@
"segments": {
"federated": "Federado",
"local": "Local",
"trending": "En tendencia"
"trending": "Tendencia"
}
},
"notifications": {
@ -28,19 +28,7 @@
"filters": {
"accessibilityLabel": "Filtrar",
"accessibilityHint": "Filtrar tipos de notificación",
"title": "Mostrar las notificaciones",
"options": {
"follow": "$t(screenTabs:me.push.follow.heading)",
"follow_request": "Solicitud de seguimiento",
"favourite": "$t(screenTabs:me.push.favourite.heading)",
"reblog": "$t(screenTabs:me.push.reblog.heading)",
"mention": "$t(screenTabs:me.push.mention.heading)",
"poll": "$t(screenTabs:me.push.poll.heading)",
"status": "Toot de usuarios suscritos",
"update": "El impulso ha sido editado",
"admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
"admin.report": "$t(screenTabs:me.push.admin.report.heading)"
}
"title": "Mostrar las notificaciones"
}
},
"me": {
@ -133,7 +121,7 @@
"listDelete": {
"heading": "Borrar lista",
"confirm": {
"title": "¿Eliminar lista \"{{list}}\"?",
"title": "¿Quieres eliminar la lista \"{{list}}\"?",
"message": "Esta acción no se podrá deshacer."
}
},
@ -254,9 +242,6 @@
"content_true": "Habilitado",
"content_false": "Deshabilitado"
},
"update": {
"title": "Actualizar a la última versión"
},
"logout": {
"button": "Cerrar sesión",
"alert": {
@ -269,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "$t(me.stacks.fontSize.name)",
"content": {
"S": "$t(me.fontSize.sizes.S)",
"M": "$t(me.fontSize.sizes.M)",
"L": "$t(me.fontSize.sizes.L)",
"XL": "$t(me.fontSize.sizes.XL)",
"XXL": "$t(me.fontSize.sizes.XXL)"
}
},
"language": {
"heading": "$t(me.stacks.language.name)"
},
"theme": {
"heading": "Apariencia",
"options": {
@ -304,9 +276,8 @@
"external": "Usar navegador"
}
},
"staticEmoji": {
"heading": "Usar emojis estáticos",
"description": "Si la aplicación falla al visualizar la lista de emojis, puedes intentar usar emojis estáticos en su lugar."
"autoplayGifv": {
"heading": "Reproduce automáticamente los GIF"
},
"feedback": {
"heading": "Petición de funciones"
@ -335,9 +306,7 @@
"moved": "Se ha trasladado",
"created_at": "Se unió el {{date}}",
"summary": {
"statuses_count": "{{count}} toots",
"following_count": "$t(shared.users.accounts.following)",
"followers_count": "$t(shared.users.accounts.followers)"
"statuses_count": "{{count}} toots"
},
"toots": {
"default": "Toots",
@ -360,6 +329,25 @@
"history": {
"name": "Historial de ediciones"
},
"report": {
"name": "",
"report": "",
"forward": {
"heading": "Enviar anónimamente al servidor remoto {{instance}}"
},
"reasons": {
"heading": "¿Qué está pasando con esta cuenta?",
"spam": "Es spam",
"other": "Es otra cosa",
"violation": "Incumple las reglas del servidor"
},
"comment": {
"heading": "¿Hay algo más que quieras añadir?"
},
"violatedRules": {
"heading": "Ha incumplido las reglas del servidor"
}
},
"search": {
"header": {
"prefix": "Buscando",

View File

@ -7,6 +7,10 @@
"action_true": "Ne plus suivre l'utilisateur"
},
"inLists": "Gérer l'utilisateur des listes",
"showBoosts": {
"action_false": "",
"action_true": ""
},
"mute": {
"action_false": "Rendre muet l'utilisateur",
"action_true": "Rendre la parole"

View File

@ -42,8 +42,7 @@
"placeholder": "Quavez-vous en tête",
"keyboardImage": {
"exceedMaximum": {
"title": "Nombre maximum de pièces jointes atteint",
"OK": "$t(common:buttons.OK)"
"title": "Nombre maximum de pièces jointes atteint"
}
}
}

View File

@ -28,19 +28,7 @@
"filters": {
"accessibilityLabel": "Filtrer",
"accessibilityHint": "Filtrer les types de notifications affichés",
"title": "Afficher les notifications",
"options": {
"follow": "$t(screenTabs:me.push.follow.heading)",
"follow_request": "Demande d'abonnement",
"favourite": "$t(screenTabs:me.push.favourite.heading)",
"reblog": "$t(screenTabs:me.push.reblog.heading)",
"mention": "$t(screenTabs:me.push.mention.heading)",
"poll": "$t(screenTabs:me.push.poll.heading)",
"status": "Pouet des utilisateurs inscrits",
"update": "Le reblog a été modifié",
"admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
"admin.report": "$t(screenTabs:me.push.admin.report.heading)"
}
"title": "Afficher les notifications"
}
},
"me": {
@ -254,9 +242,6 @@
"content_true": "Activé",
"content_false": "Désactivé"
},
"update": {
"title": "Mettre à jour vers la dernière version"
},
"logout": {
"button": "Se déconnecter",
"alert": {
@ -269,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "$t(me.stacks.fontSize.name)",
"content": {
"S": "$t(me.fontSize.sizes.S)",
"M": "$t(me.fontSize.sizes.M)",
"L": "$t(me.fontSize.sizes.L)",
"XL": "$t(me.fontSize.sizes.XL)",
"XXL": "$t(me.fontSize.sizes.XXL)"
}
},
"language": {
"heading": "$t(me.stacks.language.name)"
},
"theme": {
"heading": "Apparence",
"options": {
@ -304,9 +276,8 @@
"external": "Ouvrir dans le navigateur système"
}
},
"staticEmoji": {
"heading": "Utiliser des émojis statiques",
"description": "Si vous rencontrez des plantages fréquents de l'application lors de l'affichage de la liste d'émojis, vous pouvez essayer d'utiliser des émojis statiques."
"autoplayGifv": {
"heading": ""
},
"feedback": {
"heading": "Demande de fonctionnalités"
@ -335,9 +306,7 @@
"moved": "Utilisateur déplacé",
"created_at": "Inscrit le: {{date}}",
"summary": {
"statuses_count": "{{count}} pouets",
"following_count": "$t(shared.users.accounts.following)",
"followers_count": "$t(shared.users.accounts.followers)"
"statuses_count": "{{count}} pouets"
},
"toots": {
"default": "Pouets",
@ -360,6 +329,25 @@
"history": {
"name": "Modifier l'historique"
},
"report": {
"name": "",
"report": "",
"forward": {
"heading": ""
},
"reasons": {
"heading": "",
"spam": "",
"other": "",
"violation": ""
},
"comment": {
"heading": ""
},
"violatedRules": {
"heading": ""
}
},
"search": {
"header": {
"prefix": "Recherche en cours",

View File

@ -112,6 +112,7 @@ i18n.use(initReactI18next).init({
'zh-Hans': zh_Hans,
'zh-Hant': zh_Hant
},
returnNull: false,
returnEmptyString: false,
saveMissing: true,

View File

@ -7,6 +7,10 @@
"action_true": ""
},
"inLists": "",
"showBoosts": {
"action_false": "",
"action_true": ""
},
"mute": {
"action_false": "Muta utente",
"action_true": "Riattiva utente"

View File

@ -42,8 +42,7 @@
"placeholder": "A cosa stai pensando?",
"keyboardImage": {
"exceedMaximum": {
"title": "Hai raggiunto il numero massimo di allegati permessi",
"OK": "$t(common:buttons.OK)"
"title": "Hai raggiunto il numero massimo di allegati permessi"
}
}
}

View File

@ -28,19 +28,7 @@
"filters": {
"accessibilityLabel": "Filtri",
"accessibilityHint": "Filtra le notifiche mostrate per tipo",
"title": "",
"options": {
"follow": "$t(screenTabs:me.push.follow.heading)",
"follow_request": "Richiesta di seguirti",
"favourite": "$t(screenTabs:me.push.favourite.heading)",
"reblog": "$t(screenTabs:me.push.reblog.heading)",
"mention": "$t(screenTabs:me.push.mention.heading)",
"poll": "$t(screenTabs:me.push.poll.heading)",
"status": "Toot da utenti seguiti",
"update": "Il link è stato modificato",
"admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
"admin.report": "$t(screenTabs:me.push.admin.report.heading)"
}
"title": ""
}
},
"me": {
@ -254,9 +242,6 @@
"content_true": "Abilitato",
"content_false": "Disabilitato"
},
"update": {
"title": "Aggiorna all'ultima versione"
},
"logout": {
"button": "Esci dall'account",
"alert": {
@ -269,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "$t(me.stacks.fontSize.name)",
"content": {
"S": "$t(me.fontSize.sizes.S)",
"M": "$t(me.fontSize.sizes.M)",
"L": "$t(me.fontSize.sizes.L)",
"XL": "$t(me.fontSize.sizes.XL)",
"XXL": "$t(me.fontSize.sizes.XXL)"
}
},
"language": {
"heading": "$t(me.stacks.language.name)"
},
"theme": {
"heading": "Tema",
"options": {
@ -304,9 +276,8 @@
"external": "Nel browser di sistema"
}
},
"staticEmoji": {
"heading": "Usa emoji statiche",
"description": "Se la app crasha spesso quando all'apertura della lista di emoji, puoi provare ad attivare le emoji statiche."
"autoplayGifv": {
"heading": ""
},
"feedback": {
"heading": "Richiedi funzionalità"
@ -335,9 +306,7 @@
"moved": "Profilo trasferito",
"created_at": "Account creato il: {{date}}",
"summary": {
"statuses_count": "{{count}} toot",
"following_count": "$t(shared.users.accounts.following)",
"followers_count": "$t(shared.users.accounts.followers)"
"statuses_count": "{{count}} toot"
},
"toots": {
"default": "Toot",
@ -360,6 +329,25 @@
"history": {
"name": "Cronologia delle modifiche"
},
"report": {
"name": "",
"report": "",
"forward": {
"heading": ""
},
"reasons": {
"heading": "",
"spam": "",
"other": "",
"violation": ""
},
"comment": {
"heading": ""
},
"violatedRules": {
"heading": ""
}
},
"search": {
"header": {
"prefix": "Cerca",

View File

@ -7,6 +7,10 @@
"action_true": "ユーザーをフォロー解除"
},
"inLists": "リストのユーザーを管理",
"showBoosts": {
"action_false": "",
"action_true": ""
},
"mute": {
"action_false": "ユーザーをミュート",
"action_true": "ユーザーのミュートを解除"

View File

@ -42,8 +42,7 @@
"placeholder": "今なにかんがえてるの?",
"keyboardImage": {
"exceedMaximum": {
"title": "アップロードできるメディアの数の上限に達しました",
"OK": "$t(common:buttons.OK)"
"title": "アップロードできるメディアの数の上限に達しました"
}
}
}

View File

@ -28,19 +28,7 @@
"filters": {
"accessibilityLabel": "フィルター",
"accessibilityHint": "表示される通知の種類をフィルターする",
"title": "",
"options": {
"follow": "$t(screenTabs:me.push.follow.heading)",
"follow_request": "フォローリクエスト",
"favourite": "$t(screenTabs:me.push.favourite.heading)",
"reblog": "$t(screenTabs:me.push.reblog.heading)",
"mention": "$t(screenTabs:me.push.mention.heading)",
"poll": "$t(screenTabs:me.push.poll.heading)",
"status": "購読したユーザーのトゥート",
"update": "ブーストしたトゥートが編集されました",
"admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
"admin.report": "$t(screenTabs:me.push.admin.report.heading)"
}
"title": ""
}
},
"me": {
@ -254,9 +242,6 @@
"content_true": "有効",
"content_false": "無効"
},
"update": {
"title": "最新バージョンへのアップデート"
},
"logout": {
"button": "ログアウト",
"alert": {
@ -269,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "$t(me.stacks.fontSize.name)",
"content": {
"S": "$t(me.fontSize.sizes.S)",
"M": "$t(me.fontSize.sizes.M)",
"L": "$t(me.fontSize.sizes.L)",
"XL": "$t(me.fontSize.sizes.XL)",
"XXL": "$t(me.fontSize.sizes.XXL)"
}
},
"language": {
"heading": "$t(me.stacks.language.name)"
},
"theme": {
"heading": "外観",
"options": {
@ -304,9 +276,8 @@
"external": "システムブラウザを使用する"
}
},
"staticEmoji": {
"heading": "静的な絵文字リスト",
"description": "絵文字リストを表示しているときにアプリが頻繁にクラッシュする場合、代わりにアニメーションが無効化された絵文字リストを使用してみてください。"
"autoplayGifv": {
"heading": ""
},
"feedback": {
"heading": "機能リクエスト"
@ -335,9 +306,7 @@
"moved": "ユーザーは引っ越ししました",
"created_at": "登録日: {{date}}",
"summary": {
"statuses_count": "{{count}} 投稿",
"following_count": "$t(shared.users.accounts.following)",
"followers_count": "$t(shared.users.accounts.followers)"
"statuses_count": "{{count}} 投稿"
},
"toots": {
"default": "投稿",
@ -360,6 +329,25 @@
"history": {
"name": "編集履歴"
},
"report": {
"name": "",
"report": "",
"forward": {
"heading": ""
},
"reasons": {
"heading": "",
"spam": "",
"other": "",
"violation": ""
},
"comment": {
"heading": ""
},
"violatedRules": {
"heading": ""
}
},
"search": {
"header": {
"prefix": "検索",

View File

@ -7,6 +7,10 @@
"action_true": "사용자 팔로우 해제"
},
"inLists": "리스트의 사용자 관리",
"showBoosts": {
"action_false": "",
"action_true": ""
},
"mute": {
"action_false": "사용자 뮤트",
"action_true": "사용자 뮤트 해제"

View File

@ -42,8 +42,7 @@
"placeholder": "무엇을 생각하고 있나요?",
"keyboardImage": {
"exceedMaximum": {
"title": "최대 첨부 파일 개수를 초과함",
"OK": "$t(common:buttons.OK)"
"title": "최대 첨부 파일 개수를 초과함"
}
}
}

View File

@ -28,19 +28,7 @@
"filters": {
"accessibilityLabel": "필터",
"accessibilityHint": "받는 알림 종류 선택",
"title": "알림 표시",
"options": {
"follow": "$t(screenTabs:me.push.follow.heading)",
"follow_request": "팔로우 요청",
"favourite": "$t(screenTabs:me.push.favourite.heading)",
"reblog": "$t(screenTabs:me.push.reblog.heading)",
"mention": "$t(screenTabs:me.push.mention.heading)",
"poll": "$t(screenTabs:me.push.poll.heading)",
"status": "구독한 사용자의 툿",
"update": "부스트한 툿이 수정됨",
"admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
"admin.report": "$t(screenTabs:me.push.admin.report.heading)"
}
"title": "알림 표시"
}
},
"me": {
@ -254,9 +242,6 @@
"content_true": "활성화됨",
"content_false": "비활성화됨"
},
"update": {
"title": "최신 버전으로 업데이트"
},
"logout": {
"button": "로그아웃",
"alert": {
@ -269,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "$t(me.stacks.fontSize.name)",
"content": {
"S": "$t(me.fontSize.sizes.S)",
"M": "$t(me.fontSize.sizes.M)",
"L": "$t(me.fontSize.sizes.L)",
"XL": "$t(me.fontSize.sizes.XL)",
"XXL": "$t(me.fontSize.sizes.XXL)"
}
},
"language": {
"heading": "$t(me.stacks.language.name)"
},
"theme": {
"heading": "테마",
"options": {
@ -304,9 +276,8 @@
"external": "시스템 브라우저 사용"
}
},
"staticEmoji": {
"heading": "정적인 에모지 사용",
"description": "에모지 목록 화면에서 자주 앱이 강제 종료된다면, 정적인 에모지를 사용해보세요."
"autoplayGifv": {
"heading": ""
},
"feedback": {
"heading": "기능 제안"
@ -335,9 +306,7 @@
"moved": "유저가 이동함",
"created_at": "등록된 날: {{date}}",
"summary": {
"statuses_count": "{{count}} 툿",
"following_count": "$t(shared.users.accounts.following)",
"followers_count": "$t(shared.users.accounts.followers)"
"statuses_count": "{{count}} 툿"
},
"toots": {
"default": "툿",
@ -360,6 +329,25 @@
"history": {
"name": "수정 이력"
},
"report": {
"name": "",
"report": "",
"forward": {
"heading": ""
},
"reasons": {
"heading": "",
"spam": "",
"other": "",
"violation": ""
},
"comment": {
"heading": ""
},
"violatedRules": {
"heading": ""
}
},
"search": {
"header": {
"prefix": "검색할",

View File

@ -7,6 +7,10 @@
"action_true": "Ontvolg"
},
"inLists": "Gebruiker op lijsten beheren",
"showBoosts": {
"action_false": "Boosts van gebruiker weergeven",
"action_true": "Boosts van gebruiker verbergen"
},
"mute": {
"action_false": "Gebruiker dempen",
"action_true": "Dempen opheffen voor gebruiker"

View File

@ -42,8 +42,7 @@
"placeholder": "Wat wil je kwijt",
"keyboardImage": {
"exceedMaximum": {
"title": "Maximum aantal bijlagen bereikt",
"OK": "$t(common:buttons.OK)"
"title": "Maximum aantal bijlagen bereikt"
}
}
}

View File

@ -28,19 +28,7 @@
"filters": {
"accessibilityLabel": "Filter",
"accessibilityHint": "Filter getoonde meldingstypes",
"title": "Notificaties weergeven",
"options": {
"follow": "$t(screenTabs:me.push.follow.heading)",
"follow_request": "Volgverzoek",
"favourite": "$t(screenTabs:me.push.favourite.heading)",
"reblog": "$t(screenTabs:me.push.reblog.heading)",
"mention": "$t(screenTabs:me.push.mention.heading)",
"poll": "$t(screenTabs:me.push.poll.heading)",
"status": "Toot van geabonneerde gebruikers",
"update": "De reblog is bewerkt",
"admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
"admin.report": "$t(screenTabs:me.push.admin.report.heading)"
}
"title": "Notificaties weergeven"
}
},
"me": {
@ -254,9 +242,6 @@
"content_true": "Ingeschakeld",
"content_false": "Uitgeschakeld"
},
"update": {
"title": "Bijwerken naar de laatste versie"
},
"logout": {
"button": "Uitloggen",
"alert": {
@ -269,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "$t(me.stacks.fontSize.name)",
"content": {
"S": "$t(me.fontSize.sizes.S)",
"M": "$t(me.fontSize.sizes.M)",
"L": "$t(me.fontSize.sizes.L)",
"XL": "$t(me.fontSize.sizes.XL)",
"XXL": "$t(me.fontSize.sizes.XXL)"
}
},
"language": {
"heading": "$t(me.stacks.language.name)"
},
"theme": {
"heading": "Uiterlijk",
"options": {
@ -304,9 +276,8 @@
"external": "Systeembrowser gebruiken"
}
},
"staticEmoji": {
"heading": "Statische emoji gebruiken",
"description": "Als je vaak een app crash tegenkomt bij het bekijken van de emoji-lijst, kun je proberen om statische emojis te gebruiken."
"autoplayGifv": {
"heading": "GIF automatisch afspelen op tijdlijn"
},
"feedback": {
"heading": "Feature aanvragen"
@ -335,9 +306,7 @@
"moved": "Gebruiker is verplaatst",
"created_at": "Lid sinds {{date}}",
"summary": {
"statuses_count": "{{count}} toots",
"following_count": "$t(shared.users.accounts.following)",
"followers_count": "$t(shared.users.accounts.followers)"
"statuses_count": "{{count}} toots"
},
"toots": {
"default": "Toots",
@ -360,6 +329,25 @@
"history": {
"name": "Geschiedenis bewerken"
},
"report": {
"name": "Rapporteer {{acct}}",
"report": "Rapporteer",
"forward": {
"heading": "Anoniem doorsturen naar externe server {{instance}}"
},
"reasons": {
"heading": "Wat is er aan de hand met dit account?",
"spam": "Het is spam",
"other": "Het is iets anders",
"violation": "Het schendt de serverregels"
},
"comment": {
"heading": "Wil je nog iets anders toevoegen?"
},
"violatedRules": {
"heading": "Het is in strijd met de serverregels"
}
},
"search": {
"header": {
"prefix": "Zoeken",

View File

@ -5,10 +5,10 @@
"cancel": "Anuluj",
"discard": "Anuluj",
"continue": "Dalej",
"create": "",
"create": "Utwórz",
"delete": "Usuń",
"done": "",
"confirm": ""
"done": "Gotowe",
"confirm": "Potwierdź"
},
"customEmoji": {
"accessibilityLabel": "Własne emoji {{emoji}}"

View File

@ -1,12 +1,16 @@
{
"accessibilityHint": "",
"accessibilityHint": "Akcje dla tego tootka, takie jak jego konto lub sam tootek",
"account": {
"title": "",
"title": "Działania użytkownika",
"following": {
"action_false": "Obserwuj",
"action_true": "Przestań obserwować"
},
"inLists": "",
"inLists": "Zarządzaj kontem list",
"showBoosts": {
"action_false": "",
"action_true": ""
},
"mute": {
"action_false": "Wycisz użytkownika",
"action_true": "Wyłącz wyciszenie"
@ -15,13 +19,13 @@
"action_false": "Zablokuj użytkownika",
"action_true": "Odblokuj użytkownika",
"alert": {
"title": ""
"title": "Na pewno zablokować {{username}}?"
}
},
"reports": {
"action": "Zgłoś i zablokuj",
"alert": {
"title": ""
"title": "Potwierdzić zgłoszenie i zablokować {{username}}?"
}
}
},
@ -34,7 +38,7 @@
"succeed": "Skopiowano"
},
"instance": {
"title": "",
"title": "Opcje instancji",
"block": {
"action": "Zablokuj instancję {{instance}}",
"alert": {
@ -52,7 +56,7 @@
}
},
"status": {
"title": "",
"title": "Opcje tootka",
"edit": {
"action": "Edytuj wpis"
},
@ -64,15 +68,15 @@
}
},
"deleteEdit": {
"action": "",
"action": "Skasuj tootka i opublikuj ponownie",
"alert": {
"title": "",
"message": ""
"title": "Potwierdzasz usunięcie i ponowną publikację?",
"message": "Wszystkie podbicia i lajki zostaną usunięte, łącznie ze wszystkimi odpowiedziami."
}
},
"mute": {
"action_false": "",
"action_true": ""
"action_false": "Wycisz tootka i odpowiedzi na niego",
"action_true": "Wyłącz wyciszenie tootka i odpowiedzi na niego"
},
"pin": {
"action_false": "Przypnij wpis",

View File

@ -1,27 +1,27 @@
{
"server": {
"textInput": {
"placeholder": ""
"placeholder": "Domena instancji"
},
"whitelisted": "",
"button": "",
"whitelisted": "To może być godna zaufania instancja, z której tooot nie może pobrać danych przed zalogowaniem.",
"button": "Zaloguj",
"information": {
"name": "",
"accounts": "",
"statuses": "",
"domains": ""
"name": "Imię i nazwisko",
"accounts": "Użytkownicy",
"statuses": "Tootki",
"domains": "Uniwersa"
},
"disclaimer": {
"base": ""
"base": "Logowanie odbywa się przy użyciu przeglądarki systemowej, która nie będzie widoczna dla aplikacji."
},
"terms": {
"base": ""
"base": "Logując się, akceptujesz <0>politykę prywatności</0> i <1>regulamin usługi</1>."
}
},
"update": {
"alert": {
"title": "",
"message": ""
"title": "Zalogowano do tej instancji",
"message": "Możesz zalogować się na inne konto, zachowując już zalogowane konto"
}
}
}

View File

@ -1,8 +1,8 @@
{
"HTML": {
"accessibilityHint": "",
"expanded": "",
"moreLines": "",
"defaultHint": ""
"accessibilityHint": "Dotknij, by rozwinąć lub zwinąć zawartość",
"expanded": "{{hint}}{{moreLines}}",
"moreLines": " ({{count}} więcej linii tekstu)",
"defaultHint": "Tootek o znacznej długości"
}
}

View File

@ -1,16 +1,16 @@
{
"follow": {
"function": ""
"function": "Obserwuj użytkownika"
},
"block": {
"function": ""
"function": "Zablokuj użytkownika"
},
"button": {
"error": "",
"blocked_by": "",
"blocking": "",
"following": "",
"requested": "",
"default": ""
"error": "Błąd wczytywania",
"blocked_by": "Zablokowany przez użytkownika",
"blocking": "Odblokuj",
"following": "Przestań obserwować",
"requested": "Wycofaj żądanie",
"default": "Obserwuj"
}
}

View File

@ -9,51 +9,51 @@
}
},
"end": {
"message": ""
"message": "Koniec! Co powiesz na kubek <0 />?"
},
"lookback": {
"message": ""
"message": "Ostatnio czytane o"
},
"refresh": {
"fetchPreviousPage": "",
"refetch": ""
"fetchPreviousPage": "Nowsze",
"refetch": "Do najnowszych"
},
"shared": {
"actioned": {
"pinned": "",
"favourite": "",
"status": "",
"follow": "",
"follow_request": "",
"poll": "",
"pinned": "Przypięte",
"favourite": "{{name}} polubił Twojego tootka",
"status": "{{name}} właśnie coś opublikował(a)",
"follow": "{{name}} obserwuje Cię",
"follow_request": "{{name}} pragnie Cię obserwować",
"poll": "Ankieta w której brałeś(-aś) udział zakończyło się",
"reblog": {
"default": "",
"notification": ""
"default": "{{name}} podbił(a)",
"notification": "{{name}} podbił(a) Twojego tootka"
},
"update": "",
"update": "Podbity tootek został edytowany",
"admin.sign_up": "{{name}} dołącza do instancji",
"admin.report": ""
"admin.report": "{{name}} zgłosił(a):"
},
"actions": {
"reply": {
"accessibilityLabel": ""
"accessibilityLabel": "Odpowiedz na tego tootka"
},
"reblogged": {
"accessibilityLabel": "",
"function": "",
"accessibilityLabel": "Podbij tego tootka",
"function": "Podbij tootka",
"options": {
"title": "",
"public": "",
"unlisted": ""
"title": "Wybierz widoczność podbicia",
"public": "Podbicie publiczne",
"unlisted": "Niewidoczne podbicie"
}
},
"favourited": {
"accessibilityLabel": "",
"function": ""
"accessibilityLabel": "Dodaj do ulubionych",
"function": "Polubiony tootek"
},
"bookmarked": {
"accessibilityLabel": "",
"function": ""
"accessibilityLabel": "Dodaj tego tootka do ulubionych",
"function": "Zapisz tootka"
},
"openReport": ""
},

View File

@ -1,10 +1,10 @@
{
"heading": "",
"heading": "Ważne ogłoszenia",
"content": {
"published": "",
"published": "Opublikowano <0 />",
"button": {
"read": "",
"unread": ""
"read": "Przeczytane",
"unread": "Oznacz jako przeczytane"
}
}
}

View File

@ -2,31 +2,31 @@
"heading": {
"left": {
"alert": {
"title": "",
"title": "Porzucić zmiany?",
"buttons": {
"save": "",
"delete": ""
"save": "Zapisz wersję roboczą",
"delete": "Usuń wersję roboczą"
}
}
},
"right": {
"button": {
"default": "",
"conversation": "",
"reply": "",
"deleteEdit": "",
"edit": "",
"share": ""
"default": "Trąbnij tootka",
"conversation": "Wyślij prywatnego tootka",
"reply": "Odpowiedz",
"deleteEdit": "Trąbnij tootka",
"edit": "Trąbnij tootka",
"share": "Trąbnij tootka"
},
"alert": {
"default": {
"title": "",
"button": ""
"title": "Nie udało się trąbnąć tootka",
"button": "Spróbuj jeszcze raz"
},
"removeReply": {
"title": "",
"description": "",
"confirm": ""
"title": "Nie znaleziono odpowiedzi",
"description": "Odpowiedź mogła zostać usunięta. Czy chcesz usunąć ją z odnośnika?",
"confirm": "Usuń odnośnik"
}
}
}
@ -34,82 +34,81 @@
"content": {
"root": {
"header": {
"postingAs": "",
"postingAs": "Trąbię tootka jako @{{acct}}@{{domain}}",
"spoilerInput": {
"placeholder": ""
"placeholder": "Ostrzeżenie przed spoilerami"
},
"textInput": {
"placeholder": "",
"placeholder": "Co Ci chodzi po głowie?",
"keyboardImage": {
"exceedMaximum": {
"title": "",
"OK": ""
"title": "Osiągnięto maksymalną ilość załączników"
}
}
}
},
"footer": {
"attachments": {
"sensitive": "",
"sensitive": "Oznacz załączniki jako kontrowersyjne",
"remove": {
"accessibilityLabel": ""
"accessibilityLabel": "Usuń przesłany załącznik, numer {{attachment}}"
},
"edit": {
"accessibilityLabel": ""
"accessibilityLabel": "Edytuj przesłany załącznik, numer {{attachment}}"
},
"upload": {
"accessibilityLabel": ""
"accessibilityLabel": "Prześlij więcej załączników"
}
},
"emojis": {
"accessibilityHint": ""
"accessibilityHint": "Dotknij, by dodać emoji do tootka"
},
"poll": {
"option": {
"placeholder": {
"accessibilityLabel": "",
"single": "",
"multiple": ""
"accessibilityLabel": "Opcje ankiety {{index}}",
"single": "Pojedynczy wybór",
"multiple": "Wielokrotny wybór"
}
},
"quantity": {
"reduce": {
"accessibilityLabel": "",
"accessibilityHint": ""
"accessibilityLabel": "Zredukuj opcje ankiety do {{amount}}",
"accessibilityHint": "Osiągnięto minimalną ilość opcji ankiety, obecnie posiada {{amount}}"
},
"increase": {
"accessibilityLabel": "",
"accessibilityHint": ""
"accessibilityLabel": "Zwiększ ilość opcji ankiety do {{amount}}",
"accessibilityHint": "Osiągnięto maksymalną ilość opcji ankiety, obecnie {{amount}}"
}
},
"multiple": {
"heading": "",
"heading": "Rodzaj wyboru",
"options": {
"single": "",
"multiple": ""
"single": "Pojedynczy wybór",
"multiple": "Wielokrotny wybór"
}
},
"expiration": {
"heading": "",
"heading": "Ważność",
"options": {
"300": "",
"1800": "",
"3600": "",
"21600": "",
"86400": "",
"259200": "",
"604800": ""
"300": "5 minut",
"1800": "30 minut",
"3600": "1 godzina",
"21600": "6 godzin",
"86400": "1 dzień",
"259200": "3 dni",
"604800": "7 dni"
}
}
}
},
"actions": {
"attachment": {
"accessibilityLabel": "",
"accessibilityHint": "",
"accessibilityLabel": "Prześlij załącznik",
"accessibilityHint": "Funkcja ankiety zostanie wyłączona jeśli pojawi się jakiś załącznik",
"failed": {
"alert": {
"title": "",
"title": "Błąd przesyłania",
"button": ""
}
}

View File

@ -10,7 +10,7 @@
},
"save": {
"succeed": "",
"failed": ""
"failed": "Zapisywanie obrazka nie powiodło się"
}
}
}

View File

@ -28,89 +28,77 @@
"filters": {
"accessibilityLabel": "",
"accessibilityHint": "",
"title": "",
"options": {
"follow": "",
"follow_request": "",
"favourite": "",
"reblog": "",
"mention": "",
"poll": "",
"status": "",
"update": "",
"admin.sign_up": "",
"admin.report": ""
}
"title": ""
}
},
"me": {
"stacks": {
"bookmarks": {
"name": ""
"name": "Zalajkowane"
},
"conversations": {
"name": ""
"name": "Prywatne tootki"
},
"favourites": {
"name": ""
"name": "Ulubione"
},
"followedTags": {
"name": ""
"name": "Obserwowane hasztagi"
},
"fontSize": {
"name": ""
"name": "Rozmiar czcionki"
},
"language": {
"name": ""
"name": "Język"
},
"list": {
"name": ""
"name": "Lista: {{list}}"
},
"listAccounts": {
"name": "Użytkownicy: {{list}}"
},
"listAdd": {
"name": ""
"name": "Utwórz listę"
},
"listEdit": {
"name": "Edycja listy"
},
"lists": {
"name": ""
"name": "Listy"
},
"push": {
"name": ""
"name": "Powiadomienia Push"
},
"profile": {
"name": ""
"name": "Edytuj profil"
},
"profileName": {
"name": ""
"name": "Edytuj nazwę użytkownika"
},
"profileNote": {
"name": ""
"name": "Edytuj opis"
},
"profileFields": {
"name": ""
"name": "Edytuj metadane"
},
"settings": {
"name": ""
"name": "Ustawienia"
},
"webSettings": {
"name": ""
"name": "Ustawienia konta"
},
"switch": {
"name": ""
"name": "Przełącz konto"
}
},
"fontSize": {
"demo": "",
"demo": "<p>Oto przykładowy tootek 😊 Wybierz opcje wielkości czcionki z listy poniżej.<br /><br />To ustawienie wpłynie jedynie na zawartość Twoich tootków, ale nie na rozmiar innych komunikatów z apki.</p>",
"sizes": {
"S": "",
"M": "",
"L": "",
"XL": "",
"XXL": ""
"S": "S",
"M": "M (Domyślna)",
"L": "L",
"XL": "XL",
"XXL": "XXL"
}
},
"listAccounts": {
@ -139,55 +127,55 @@
},
"profile": {
"feedback": {
"succeed": "",
"failed": ""
"succeed": "Zaktualizowano {{type}}",
"failed": "Aktualizacja {{type}} nie powiodła się, prosimy spróbować ponownie"
},
"root": {
"name": {
"title": ""
"title": "Wyświetlana nazwa"
},
"avatar": {
"title": "",
"description": ""
"title": "Zdjęcie profilowe",
"description": "Zostanie zmniejszone do 400x400 px"
},
"header": {
"title": "",
"description": ""
"title": "Zdjęcie w tle",
"description": "Zostanie zmniejszony do 1500x500 px"
},
"note": {
"title": ""
"title": "Opis"
},
"fields": {
"title": "",
"total_one": "",
"total_other": ""
"title": "Metadane",
"total_one": "Pole {{count}}",
"total_other": "{{count}} pola"
},
"visibility": {
"title": "",
"title": "Domyślna widoczność tootków",
"options": {
"public": "",
"unlisted": "",
"private": ""
"public": "Publiczne",
"unlisted": "Niepubliczne",
"private": "Tylko dla obserwujących"
}
},
"sensitive": {
"title": ""
"title": "Publikuję rzeczy 18+"
},
"lock": {
"title": "",
"description": ""
"title": "Zablokuj konto",
"description": "Wymaga ręcznego zatwierdzania obserwujących"
},
"bot": {
"title": "",
"description": ""
"title": "Konto bota",
"description": "To konto podejmuje głównie zautomatyzowane działania i może nie być nadzorowane"
}
},
"fields": {
"group": "",
"label": "",
"content": ""
"group": "Grupa {{index}}",
"label": "Nazwa",
"content": "Link"
},
"mediaSelectionFailed": ""
"mediaSelectionFailed": "Nie udało się przetworzyć obrazka. Prosimy, spróbuj raz jeszcze"
},
"push": {
"notAvailable": "",
@ -254,9 +242,6 @@
"content_true": "",
"content_false": ""
},
"update": {
"title": ""
},
"logout": {
"button": "",
"alert": {
@ -269,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "",
"content": {
"S": "",
"M": "",
"L": "",
"XL": "",
"XXL": ""
}
},
"language": {
"heading": ""
},
"theme": {
"heading": "",
"options": {
@ -304,21 +276,20 @@
"external": ""
}
},
"staticEmoji": {
"heading": "",
"description": ""
"autoplayGifv": {
"heading": ""
},
"feedback": {
"heading": ""
},
"support": {
"heading": ""
"heading": "Wesprzyj tooot!"
},
"contact": {
"heading": ""
"heading": "Skontaktuj się z nami"
},
"version": "",
"instanceVersion": ""
"version": "Wersja: v{{version}}",
"instanceVersion": "Wersja Mastodona: v{{version}}"
},
"switch": {
"existing": "",
@ -335,9 +306,7 @@
"moved": "",
"created_at": "",
"summary": {
"statuses_count": "",
"following_count": "",
"followers_count": ""
"statuses_count": ""
},
"toots": {
"default": "",
@ -360,6 +329,25 @@
"history": {
"name": ""
},
"report": {
"name": "",
"report": "",
"forward": {
"heading": ""
},
"reasons": {
"heading": "",
"spam": "",
"other": "",
"violation": ""
},
"comment": {
"heading": ""
},
"violatedRules": {
"heading": ""
}
},
"search": {
"header": {
"prefix": "",

View File

@ -7,6 +7,10 @@
"action_true": ""
},
"inLists": "",
"showBoosts": {
"action_false": "",
"action_true": ""
},
"mute": {
"action_false": "Silenciar usuário",
"action_true": "Desativar o silêncio do usuário"

View File

@ -42,8 +42,7 @@
"placeholder": "No que você está pensando",
"keyboardImage": {
"exceedMaximum": {
"title": "Quantidade máxima de anexos atingida",
"OK": "$t(common:buttons.OK)"
"title": "Quantidade máxima de anexos atingida"
}
}
}

View File

@ -28,19 +28,7 @@
"filters": {
"accessibilityLabel": "Filtro",
"accessibilityHint": "Filtrar notificações por tipos",
"title": "",
"options": {
"follow": "$t(screenTabs:me.push.follow.heading)",
"follow_request": "Solicitações de seguidores pendentes",
"favourite": "$t(screenTabs:me.push.favourite.heading)",
"reblog": "$t(screenTabs:me.push.reblog.heading)",
"mention": "$t(screenTabs:me.push.mention.heading)",
"poll": "$t(screenTabs:me.push.poll.heading)",
"status": "Toot de usuários inscritos",
"update": "Toot foi editado",
"admin.sign_up": "$t(screenTabs:me.push.admin.sign_up.heading)",
"admin.report": "$t(screenTabs:me.push.admin.report.heading)"
}
"title": ""
}
},
"me": {
@ -254,9 +242,6 @@
"content_true": "Habilitado",
"content_false": "Desabilitado"
},
"update": {
"title": "Atualize para a versão mais recente"
},
"logout": {
"button": "Sair",
"alert": {
@ -269,19 +254,6 @@
}
},
"settings": {
"fontsize": {
"heading": "$t(me.stacks.fontSize.name)",
"content": {
"S": "$t(me.fontSize.sizes.S)",
"M": "$t(me.fontSize.sizes.M)",
"L": "$t(me.fontSize.sizes.L)",
"XL": "$t(me.fontSize.sizes.XL)",
"XXL": "$t(me.fontSize.sizes.XXL)"
}
},
"language": {
"heading": "$t(me.stacks.language.name)"
},
"theme": {
"heading": "Aparência",
"options": {
@ -304,9 +276,8 @@
"external": "Usar navegador do sistema"
}
},
"staticEmoji": {
"heading": "Usar emojis estáticos",
"description": "Se você encontrar falhas frequentes de apps ao visualizar a lista de emojis, você pode tentar usar emojis estáticos."
"autoplayGifv": {
"heading": ""
},
"feedback": {
"heading": "Pedidos de Funcionalidades"
@ -335,9 +306,7 @@
"moved": "Usuário movido",
"created_at": "Registrado em: {{date}}",
"summary": {
"statuses_count": "{{count}} toots",
"following_count": "$t(shared.users.accounts.following)",
"followers_count": "$t(shared.users.accounts.followers)"
"statuses_count": "{{count}} toots"
},
"toots": {
"default": "Toots",
@ -360,6 +329,25 @@
"history": {
"name": "Histórico de Edição"
},
"report": {
"name": "",
"report": "",
"forward": {
"heading": ""
},
"reasons": {
"heading": "",
"spam": "",
"other": "",
"violation": ""
},
"comment": {
"heading": ""
},
"violatedRules": {
"heading": ""
}
},
"search": {
"header": {
"prefix": "Procurando",

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