Update i18next type

This commit is contained in:
xmflsct 2022-12-23 15:53:40 +01:00
parent b388853429
commit e32125ad17
49 changed files with 1054 additions and 896 deletions

View File

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

View File

@ -1,8 +1,46 @@
import 'i18next' 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' { declare module 'i18next' {
interface CustomTypeOptions { 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 returnNull: false
returnEmptyString: false
} }
} }

View File

@ -39,7 +39,12 @@ export interface Props {
} }
const Screens: React.FC<Props> = ({ localCorrupt }) => { const Screens: React.FC<Props> = ({ localCorrupt }) => {
const { t } = useTranslation('screens') const { t } = useTranslation([
'common',
'screens',
'screenAnnouncements',
'screenAccountSelection'
])
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const instanceActive = useSelector(getInstanceActive) const instanceActive = useSelector(getInstanceActive)
const { colors, theme } = useTheme() const { colors, theme } = useTheme()
@ -55,7 +60,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
// Prevent screenshot alert // Prevent screenshot alert
useEffect(() => { useEffect(() => {
const screenshotListener = addScreenshotListener(() => 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' } { text: t('common:buttons.confirm'), style: 'destructive' }
]) ])
) )
@ -68,7 +73,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
const showLocalCorrect = () => { const showLocalCorrect = () => {
if (localCorrupt) { if (localCorrupt) {
displayMessage({ displayMessage({
message: t('localCorrupt.message'), message: t('screens:localCorrupt.message'),
description: localCorrupt.length ? localCorrupt : undefined, description: localCorrupt.length ? localCorrupt : undefined,
type: 'danger' type: 'danger'
}) })
@ -176,7 +181,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
if (!typesImage.includes(mime.split('/')[1])) { if (!typesImage.includes(mime.split('/')[1])) {
console.warn('Image type not supported:', mime.split('/')[1]) console.warn('Image type not supported:', mime.split('/')[1])
displayMessage({ displayMessage({
message: t('shareError.imageNotSupported', { message: t('screens:shareError.imageNotSupported', {
type: mime.split('/')[1] type: mime.split('/')[1]
}), }),
type: 'danger' type: 'danger'
@ -188,7 +193,7 @@ const Screens: React.FC<Props> = ({ localCorrupt }) => {
if (!typesVideo.includes(mime.split('/')[1])) { if (!typesVideo.includes(mime.split('/')[1])) {
console.warn('Video type not supported:', mime.split('/')[1]) console.warn('Video type not supported:', mime.split('/')[1])
displayMessage({ displayMessage({
message: t('shareError.videoNotSupported', { message: t('screens:shareError.videoNotSupported', {
type: mime.split('/')[1] type: mime.split('/')[1]
}), }),
type: 'danger' type: 'danger'

View File

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

View File

@ -25,7 +25,7 @@ import EmojisContext from './helpers/EmojisContext'
const EmojisList = () => { const EmojisList = () => {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const { reduceMotionEnabled } = useAccessibility() const { reduceMotionEnabled } = useAccessibility()
const { t } = useTranslation() const { t } = useTranslation(['common', 'screenCompose'])
const { emojisState, emojisDispatch } = useContext(EmojisContext) const { emojisState, emojisDispatch } = useContext(EmojisContext)
const { colors } = useTheme() const { colors } = useTheme()

View File

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

View File

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

View File

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

View File

@ -45,7 +45,8 @@ const TimelineFooter = React.memo(
) : ( ) : (
<CustomText fontStyle='S' style={{ color: colors.secondary }}> <CustomText fontStyle='S' style={{ color: colors.secondary }}>
<Trans <Trans
i18nKey='componentTimeline:end.message' ns='componentTimeline'
i18nKey='end.message'
components={[ components={[
<Icon name='Coffee' size={StyleConstants.Font.Size.S} color={colors.secondary} /> <Icon name='Coffee' size={StyleConstants.Font.Size.S} color={colors.secondary} />
]} ]}

View File

@ -28,7 +28,7 @@ const TimelineActions: React.FC = () => {
if (!queryKey || !status || disableDetails) return null if (!queryKey || !status || disableDetails) return null
const navigation = useNavigation<StackNavigationProp<RootStackParamList>>() const navigation = useNavigation<StackNavigationProp<RootStackParamList>>()
const { t } = useTranslation('componentTimeline') const { t } = useTranslation(['common', 'componentTimeline'])
const { colors, theme } = useTheme() const { colors, theme } = useTheme()
const iconColor = colors.secondary const iconColor = colors.secondary
@ -54,13 +54,13 @@ const TimelineActions: React.FC = () => {
queryClient.invalidateQueries(tempQueryKey) queryClient.invalidateQueries(tempQueryKey)
} }
}, },
onError: (err: any, params, oldData) => { onError: (err: any, params) => {
const correctParam = params as MutationVarsTimelineUpdateStatusProperty const correctParam = params as MutationVarsTimelineUpdateStatusProperty
displayMessage({ displayMessage({
theme, theme,
type: 'error', type: 'error',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t(`shared.actions.${correctParam.payload.property}.function`) function: t(`componentTimeline:shared.actions.${correctParam.payload.property}.function`)
}), }),
...(err.status && ...(err.status &&
typeof err.status === 'number' && typeof err.status === 'number' &&
@ -94,10 +94,10 @@ const TimelineActions: React.FC = () => {
if (!status.reblogged) { if (!status.reblogged) {
showActionSheetWithOptions( showActionSheetWithOptions(
{ {
title: t('shared.actions.reblogged.options.title'), title: t('componentTimeline:shared.actions.reblogged.options.title'),
options: [ options: [
t('shared.actions.reblogged.options.public'), t('componentTimeline:shared.actions.reblogged.options.public'),
t('shared.actions.reblogged.options.unlisted'), t('componentTimeline:shared.actions.reblogged.options.unlisted'),
t('common:buttons.cancel') t('common:buttons.cancel')
], ],
cancelButtonIndex: 2, cancelButtonIndex: 2,
@ -269,7 +269,7 @@ const TimelineActions: React.FC = () => {
<Pressable <Pressable
{...(highlighted {...(highlighted
? { ? {
accessibilityLabel: t('shared.actions.reply.accessibilityLabel'), accessibilityLabel: t('componentTimeline:shared.actions.reply.accessibilityLabel'),
accessibilityRole: 'button' accessibilityRole: 'button'
} }
: { accessibilityLabel: '' })} : { accessibilityLabel: '' })}
@ -281,7 +281,9 @@ const TimelineActions: React.FC = () => {
<Pressable <Pressable
{...(highlighted {...(highlighted
? { ? {
accessibilityLabel: t('shared.actions.reblogged.accessibilityLabel'), accessibilityLabel: t(
'componentTimeline:shared.actions.reblogged.accessibilityLabel'
),
accessibilityRole: 'button' accessibilityRole: 'button'
} }
: { accessibilityLabel: '' })} : { accessibilityLabel: '' })}
@ -296,7 +298,9 @@ const TimelineActions: React.FC = () => {
<Pressable <Pressable
{...(highlighted {...(highlighted
? { ? {
accessibilityLabel: t('shared.actions.favourited.accessibilityLabel'), accessibilityLabel: t(
'componentTimeline:shared.actions.favourited.accessibilityLabel'
),
accessibilityRole: 'button' accessibilityRole: 'button'
} }
: { accessibilityLabel: '' })} : { accessibilityLabel: '' })}
@ -308,7 +312,9 @@ const TimelineActions: React.FC = () => {
<Pressable <Pressable
{...(highlighted {...(highlighted
? { ? {
accessibilityLabel: t('shared.actions.bookmarked.accessibilityLabel'), accessibilityLabel: t(
'componentTimeline:shared.actions.bookmarked.accessibilityLabel'
),
accessibilityRole: 'button' accessibilityRole: 'button'
} }
: { accessibilityLabel: '' })} : { accessibilityLabel: '' })}

View File

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

View File

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

View File

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

View File

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

View File

@ -39,7 +39,7 @@ const menuAccount = ({
const navigation = const navigation =
useNavigation<NativeStackNavigationProp<TabSharedStackParamList, any, undefined>>() useNavigation<NativeStackNavigationProp<TabSharedStackParamList, any, undefined>>()
const { t } = useTranslation('componentContextMenu') const { t } = useTranslation(['common', 'componentContextMenu', 'componentRelationship'])
const menus: ContextMenu[][] = [[]] const menus: ContextMenu[][] = [[]]
@ -62,11 +62,15 @@ const menuAccount = ({
displayMessage({ displayMessage({
type: 'success', type: 'success',
message: t('common:message.success.message', { message: t('common:message.success.message', {
function: t(`account.${theParams.payload.property}.action`, { function: t(
...(theParams.payload.property !== 'reports' && { `componentContextMenu:account.${theParams.payload.property}.action`,
context: (theParams.payload.currentValue || false).toString() theParams.payload.property !== 'reports'
}) ? {
}) defaultValue: 'false',
context: (theParams.payload.currentValue || false).toString()
}
: { defaultValue: 'false' }
)
}) })
}) })
}, },
@ -75,11 +79,15 @@ const menuAccount = ({
displayMessage({ displayMessage({
type: 'danger', type: 'danger',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t(`account.${theParams.payload.property}.action`, { function: t(
...(theParams.payload.property !== 'reports' && { `componentContextMenu:account.${theParams.payload.property}.action`,
context: (theParams.payload.currentValue || false).toString() theParams.payload.property !== 'reports'
}) ? {
}) defaultValue: 'false',
context: (theParams.payload.currentValue || false).toString()
}
: { defaultValue: 'false' }
)
}), }),
...(err.status && ...(err.status &&
typeof err.status === 'number' && typeof err.status === 'number' &&
@ -109,7 +117,7 @@ const menuAccount = ({
displayMessage({ displayMessage({
type: 'danger', type: 'danger',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t(`${action}.function`) function: t(`componentContextMenu:${action}.function` as any)
}), }),
...(err.status && ...(err.status &&
typeof err.status === 'number' && typeof err.status === 'number' &&
@ -138,7 +146,8 @@ const menuAccount = ({
hidden: false hidden: false
}, },
title: !data?.requested title: !data?.requested
? t('account.following.action', { ? t('componentContextMenu:account.following.action', {
defaultValue: 'false',
context: (data?.following || false).toString() context: (data?.following || false).toString()
}) })
: t('componentRelationship:button.requested'), : t('componentRelationship:button.requested'),
@ -158,7 +167,7 @@ const menuAccount = ({
destructive: false, destructive: false,
hidden: !isFetched || !data?.following hidden: !isFetched || !data?.following
}, },
title: t('account.inLists'), title: t('componentContextMenu:account.inLists'),
icon: 'checklist' icon: 'checklist'
}) })
menus[0].push({ menus[0].push({
@ -175,7 +184,8 @@ const menuAccount = ({
destructive: false, destructive: false,
hidden: false hidden: false
}, },
title: t('account.mute.action', { title: t('componentContextMenu:account.mute.action', {
defaultValue: 'false',
context: (data?.muting || false).toString() context: (data?.muting || false).toString()
}), }),
icon: data?.muting ? 'eye' : 'eye.slash' icon: data?.muting ? 'eye' : 'eye.slash'
@ -188,27 +198,32 @@ const menuAccount = ({
key: 'account-block', key: 'account-block',
item: { item: {
onSelect: () => onSelect: () =>
Alert.alert(t('account.block.alert.title', { username: account.username }), undefined, [ Alert.alert(
{ t('componentContextMenu:account.block.alert.title', { username: account.username }),
text: t('common:buttons.confirm'), undefined,
style: 'destructive', [
onPress: () => {
timelineMutation.mutate({ text: t('common:buttons.confirm'),
type: 'updateAccountProperty', style: 'destructive',
queryKey, onPress: () =>
id: account.id, timelineMutation.mutate({
payload: { property: 'block', currentValue: data?.blocking } type: 'updateAccountProperty',
}) queryKey,
}, id: account.id,
{ payload: { property: 'block', currentValue: data?.blocking }
text: t('common:buttons.cancel') })
} },
]), {
text: t('common:buttons.cancel')
}
]
),
disabled: Platform.OS !== 'android' ? !data || !isFetched : false, disabled: Platform.OS !== 'android' ? !data || !isFetched : false,
destructive: !data?.blocking, destructive: !data?.blocking,
hidden: false hidden: false
}, },
title: t('account.block.action', { title: t('componentContextMenu:account.block.action', {
defaultValue: 'false',
context: (data?.blocking || false).toString() context: (data?.blocking || false).toString()
}), }),
icon: data?.blocking ? 'checkmark.circle' : 'xmark.circle' icon: data?.blocking ? 'checkmark.circle' : 'xmark.circle'
@ -221,7 +236,7 @@ const menuAccount = ({
destructive: true, destructive: true,
hidden: false hidden: false
}, },
title: t('account.reports.action'), title: t('componentContextMenu:account.reports.action'),
icon: 'flag' icon: 'flag'
} }
]) ])

View File

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

View File

@ -28,7 +28,7 @@ const menuStatus = ({
const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList, 'Screen-Tabs'>>() const navigation = useNavigation<NativeStackNavigationProp<RootStackParamList, 'Screen-Tabs'>>()
const { theme } = useTheme() const { theme } = useTheme()
const { t } = useTranslation('componentContextMenu') const { t } = useTranslation(['common', 'componentContextMenu'])
const queryClient = useQueryClient() const queryClient = useQueryClient()
const mutation = useTimelineMutation({ const mutation = useTimelineMutation({
@ -41,7 +41,7 @@ const menuStatus = ({
theme, theme,
type: 'error', type: 'error',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t(`status.${theFunction}.action`) function: t(`componentContextMenu:status.${theFunction}.action` as any)
}), }),
...(err?.status && ...(err?.status &&
typeof err.status === 'number' && typeof err.status === 'number' &&
@ -100,81 +100,89 @@ const menuStatus = ({
destructive: false, destructive: false,
hidden: !canEditPost hidden: !canEditPost
}, },
title: t('status.edit.action'), title: t('componentContextMenu:status.edit.action'),
icon: 'square.and.pencil' icon: 'square.and.pencil'
}, },
{ {
key: 'status-delete-edit', key: 'status-delete-edit',
item: { item: {
onSelect: () => onSelect: () =>
Alert.alert(t('status.deleteEdit.alert.title'), t('status.deleteEdit.alert.message'), [ Alert.alert(
{ t('componentContextMenu:status.deleteEdit.alert.title'),
text: t('common:buttons.confirm'), t('componentContextMenu:status.deleteEdit.alert.message'),
style: 'destructive', [
onPress: async () => { {
let replyToStatus: Mastodon.Status | undefined = undefined text: t('common:buttons.confirm'),
if (status.in_reply_to_id) { style: 'destructive',
replyToStatus = await apiInstance<Mastodon.Status>({ onPress: async () => {
method: 'get', let replyToStatus: Mastodon.Status | undefined = undefined
url: `statuses/${status.in_reply_to_id}` if (status.in_reply_to_id) {
}).then(res => res.body) replyToStatus = await apiInstance<Mastodon.Status>({
} method: 'get',
mutation url: `statuses/${status.in_reply_to_id}`
.mutateAsync({ }).then(res => res.body)
type: 'deleteItem', }
source: 'statuses', mutation
queryKey, .mutateAsync({
id: status.id type: 'deleteItem',
}) source: 'statuses',
.then(res => { queryKey,
navigation.navigate('Screen-Compose', { id: status.id
type: 'deleteEdit',
incomingStatus: res.body as Mastodon.Status,
...(replyToStatus && { replyToStatus }),
queryKey
}) })
}) .then(res => {
navigation.navigate('Screen-Compose', {
type: 'deleteEdit',
incomingStatus: res.body as Mastodon.Status,
...(replyToStatus && { replyToStatus }),
queryKey
})
})
}
},
{
text: t('common:buttons.cancel')
} }
}, ]
{ ),
text: t('common:buttons.cancel')
}
]),
disabled: false, disabled: false,
destructive: true, destructive: true,
hidden: false hidden: false
}, },
title: t('status.deleteEdit.action'), title: t('componentContextMenu:status.deleteEdit.action'),
icon: 'pencil.and.outline' icon: 'pencil.and.outline'
}, },
{ {
key: 'status-delete', key: 'status-delete',
item: { item: {
onSelect: () => onSelect: () =>
Alert.alert(t('status.delete.alert.title'), t('status.delete.alert.message'), [ Alert.alert(
{ t('componentContextMenu:status.delete.alert.title'),
text: t('common:buttons.confirm'), t('componentContextMenu:status.delete.alert.message'),
style: 'destructive', [
onPress: async () => { {
mutation.mutate({ text: t('common:buttons.confirm'),
type: 'deleteItem', style: 'destructive',
source: 'statuses', onPress: async () => {
queryKey, mutation.mutate({
rootQueryKey, type: 'deleteItem',
id: status.id source: 'statuses',
}) queryKey,
rootQueryKey,
id: status.id
})
}
},
{
text: t('common:buttons.cancel'),
style: 'default'
} }
}, ]
{ ),
text: t('common:buttons.cancel'),
style: 'default'
}
]),
disabled: false, disabled: false,
destructive: true, destructive: true,
hidden: false hidden: false
}, },
title: t('status.delete.action'), title: t('componentContextMenu:status.delete.action'),
icon: 'trash' icon: 'trash'
} }
]) ])
@ -200,7 +208,8 @@ const menuStatus = ({
destructive: false, destructive: false,
hidden: false hidden: false
}, },
title: t('status.mute.action', { title: t('componentContextMenu:status.mute.action', {
defaultValue: 'false',
context: (status.muted || false).toString() context: (status.muted || false).toString()
}), }),
icon: status.muted ? 'speaker' : 'speaker.slash' icon: status.muted ? 'speaker' : 'speaker.slash'
@ -226,7 +235,8 @@ const menuStatus = ({
destructive: false, destructive: false,
hidden: status.visibility !== 'public' && status.visibility !== 'unlisted' hidden: status.visibility !== 'public' && status.visibility !== 'unlisted'
}, },
title: t('status.pin.action', { title: t('componentContextMenu:status.pin.action', {
defaultValue: 'false',
context: (status.pinned || false).toString() context: (status.pinned || false).toString()
}), }),
icon: status.pinned ? 'pin.slash' : 'pin' icon: status.pinned ? 'pin.slash' : 'pin'

View File

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

View File

@ -16,17 +16,15 @@ export interface Props {
const ActionsAltText: React.FC<Props> = ({ text }) => { const ActionsAltText: React.FC<Props> = ({ text }) => {
const navigation = useNavigation() const navigation = useNavigation()
const { t } = useTranslation('screenActions') const { t } = useTranslation(['common', 'screenActions'])
const { colors } = useTheme() const { colors } = useTheme()
return ( return (
<> <>
<MenuContainer> <MenuContainer>
<MenuHeader heading={t(`content.altText.heading`)} /> <MenuHeader heading={t(`screenActions:content.altText.heading`)} />
<ScrollView style={{ maxHeight: Dimensions.get('window').height / 2 }}> <ScrollView style={{ maxHeight: Dimensions.get('window').height / 2 }}>
<CustomText style={{ color: colors.primaryDefault }}> <CustomText style={{ color: colors.primaryDefault }}>{text}</CustomText>
{text}
</CustomText>
</ScrollView> </ScrollView>
</MenuContainer> </MenuContainer>
<Button <Button

View File

@ -87,7 +87,8 @@ const ScreenAnnouncements: React.FC<RootStackScreenProps<'Screen-Announcements'>
}} }}
> >
<Trans <Trans
i18nKey='screenAnnouncements:content.published' ns='screenAnnouncements'
i18nKey='content.published'
components={[<RelativeTime time={item.published_at} />]} components={[<RelativeTime time={item.published_at} />]}
/> />
</CustomText> </CustomText>

View File

@ -39,7 +39,7 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
route: { params }, route: { params },
navigation navigation
}) => { }) => {
const { t } = useTranslation('screenCompose') const { t } = useTranslation(['common', 'screenCompose'])
const { colors } = useTheme() const { colors } = useTheme()
const queryClient = useQueryClient() const queryClient = useQueryClient()
@ -212,9 +212,9 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
navigation.goBack() navigation.goBack()
return return
} else { } else {
Alert.alert(t('heading.left.alert.title'), undefined, [ Alert.alert(t('screenCompose:heading.left.alert.title'), undefined, [
{ {
text: t('heading.left.alert.buttons.delete'), text: t('screenCompose:heading.left.alert.buttons.delete'),
style: 'destructive', style: 'destructive',
onPress: () => { onPress: () => {
removeDraft() removeDraft()
@ -222,7 +222,7 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
} }
}, },
{ {
text: t('heading.left.alert.buttons.save'), text: t('screenCompose:heading.left.alert.buttons.save'),
onPress: () => { onPress: () => {
saveDraft() saveDraft()
navigation.goBack() navigation.goBack()
@ -266,7 +266,7 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
: 'default' : 'default'
: params.type)) || : params.type)) ||
'default' 'default'
}` }` as any
)} )}
onPress={() => { onPress={() => {
composeDispatch({ type: 'posting', payload: true }) composeDispatch({ type: 'posting', payload: true })
@ -302,8 +302,8 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
.catch(error => { .catch(error => {
if (error?.removeReply) { if (error?.removeReply) {
Alert.alert( Alert.alert(
t('heading.right.alert.removeReply.title'), t('screenCompose:heading.right.alert.removeReply.title'),
t('heading.right.alert.removeReply.description'), t('screenCompose:heading.right.alert.removeReply.description'),
[ [
{ {
text: t('common:buttons.cancel'), text: t('common:buttons.cancel'),
@ -313,7 +313,7 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
style: 'destructive' style: 'destructive'
}, },
{ {
text: t('heading.right.alert.removeReply.confirm'), text: t('screenCompose:heading.right.alert.removeReply.confirm'),
onPress: () => { onPress: () => {
composeDispatch({ type: 'removeReply' }) composeDispatch({ type: 'removeReply' })
composeDispatch({ type: 'posting', payload: false }) composeDispatch({ type: 'posting', payload: false })
@ -326,10 +326,8 @@ const ScreenCompose: React.FC<RootStackScreenProps<'Screen-Compose'>> = ({
haptics('Error') haptics('Error')
handleError({ message: 'Posting error', captureResponse: true }) handleError({ message: 'Posting error', captureResponse: true })
composeDispatch({ type: 'posting', payload: false }) composeDispatch({ type: 'posting', payload: false })
Alert.alert(t('heading.right.alert.default.title'), undefined, [ Alert.alert(t('screenCompose:heading.right.alert.default.title'), undefined, [
{ { text: t('screenCompose:heading.right.alert.default.button') }
text: t('heading.right.alert.default.button')
}
]) ])
} }
}) })

View File

@ -16,7 +16,7 @@ import chooseAndUploadAttachment from './Footer/addAttachment'
const ComposeActions: React.FC = () => { const ComposeActions: React.FC = () => {
const { showActionSheetWithOptions } = useActionSheet() const { showActionSheetWithOptions } = useActionSheet()
const { composeState, composeDispatch } = useContext(ComposeContext) const { composeState, composeDispatch } = useContext(ComposeContext)
const { t } = useTranslation('screenCompose') const { t } = useTranslation(['common', 'screenCompose'])
const { colors } = useTheme() const { colors } = useTheme()
const instanceConfigurationStatusMaxAttachments = useSelector( const instanceConfigurationStatusMaxAttachments = useSelector(
getInstanceConfigurationStatusMaxAttachments, getInstanceConfigurationStatusMaxAttachments,
@ -81,12 +81,12 @@ const ComposeActions: React.FC = () => {
if (!composeState.visibilityLock) { if (!composeState.visibilityLock) {
showActionSheetWithOptions( showActionSheetWithOptions(
{ {
title: t('content.root.actions.visibility.title'), title: t('screenCompose:content.root.actions.visibility.title'),
options: [ options: [
t('content.root.actions.visibility.options.public'), t('screenCompose:content.root.actions.visibility.options.public'),
t('content.root.actions.visibility.options.unlisted'), t('screenCompose:content.root.actions.visibility.options.unlisted'),
t('content.root.actions.visibility.options.private'), t('screenCompose:content.root.actions.visibility.options.private'),
t('content.root.actions.visibility.options.direct'), t('screenCompose:content.root.actions.visibility.options.direct'),
t('common:buttons.cancel') t('common:buttons.cancel')
], ],
cancelButtonIndex: 4, cancelButtonIndex: 4,
@ -160,8 +160,8 @@ const ComposeActions: React.FC = () => {
> >
<Pressable <Pressable
accessibilityRole='button' accessibilityRole='button'
accessibilityLabel={t('content.root.actions.attachment.accessibilityLabel')} accessibilityLabel={t('screenCompose:content.root.actions.attachment.accessibilityLabel')}
accessibilityHint={t('content.root.actions.attachment.accessibilityHint')} accessibilityHint={t('screenCompose:content.root.actions.attachment.accessibilityHint')}
accessibilityState={{ accessibilityState={{
disabled: composeState.poll.active disabled: composeState.poll.active
}} }}
@ -171,8 +171,8 @@ const ComposeActions: React.FC = () => {
/> />
<Pressable <Pressable
accessibilityRole='button' accessibilityRole='button'
accessibilityLabel={t('content.root.actions.poll.accessibilityLabel')} accessibilityLabel={t('screenCompose:content.root.actions.poll.accessibilityLabel')}
accessibilityHint={t('content.root.actions.poll.accessibilityHint')} accessibilityHint={t('screenCompose:content.root.actions.poll.accessibilityHint')}
accessibilityState={{ accessibilityState={{
disabled: composeState.attachments.uploads.length ? true : false, disabled: composeState.attachments.uploads.length ? true : false,
expanded: composeState.poll.active expanded: composeState.poll.active
@ -183,7 +183,7 @@ const ComposeActions: React.FC = () => {
/> />
<Pressable <Pressable
accessibilityRole='button' accessibilityRole='button'
accessibilityLabel={t('content.root.actions.visibility.accessibilityLabel', { accessibilityLabel={t('screenCompose:content.root.actions.visibility.accessibilityLabel', {
visibility: composeState.visibility visibility: composeState.visibility
})} })}
accessibilityState={{ disabled: composeState.visibilityLock }} accessibilityState={{ disabled: composeState.visibilityLock }}
@ -199,7 +199,7 @@ const ComposeActions: React.FC = () => {
/> />
<Pressable <Pressable
accessibilityRole='button' accessibilityRole='button'
accessibilityLabel={t('content.root.actions.spoiler.accessibilityLabel')} accessibilityLabel={t('screenCompose:content.root.actions.spoiler.accessibilityLabel')}
accessibilityState={{ expanded: composeState.spoiler.active }} accessibilityState={{ expanded: composeState.spoiler.active }}
style={styles.button} style={styles.button}
onPress={spoilerOnPress} onPress={spoilerOnPress}
@ -213,8 +213,8 @@ const ComposeActions: React.FC = () => {
/> />
<Pressable <Pressable
accessibilityRole='button' accessibilityRole='button'
accessibilityLabel={t('content.root.actions.emoji.accessibilityLabel')} accessibilityLabel={t('screenCompose:content.root.actions.emoji.accessibilityLabel')}
accessibilityHint={t('content.root.actions.emoji.accessibilityHint')} accessibilityHint={t('screenCompose:content.root.actions.emoji.accessibilityHint')}
accessibilityState={{ accessibilityState={{
disabled: emojis.current?.length ? false : true, disabled: emojis.current?.length ? false : true,
expanded: emojisState.targetIndex !== -1 expanded: emojisState.targetIndex !== -1

View File

@ -21,7 +21,7 @@ const ComposePoll: React.FC = () => {
}, },
composeDispatch composeDispatch
} = useContext(ComposeContext) } = useContext(ComposeContext)
const { t } = useTranslation('screenCompose') const { t } = useTranslation(['common', 'screenCompose'])
const { colors, mode } = useTheme() const { colors, mode } = useTheme()
const instanceConfigurationPoll = useSelector(getInstanceConfigurationPoll, () => true) const instanceConfigurationPoll = useSelector(getInstanceConfigurationPoll, () => true)
@ -71,7 +71,7 @@ const ComposePoll: React.FC = () => {
/> />
<TextInput <TextInput
accessibilityLabel={t( accessibilityLabel={t(
'content.root.footer.poll.option.placeholder.accessibilityLabel', 'screenCompose:content.root.footer.poll.option.placeholder.accessibilityLabel',
{ index: i + 1 } { index: i + 1 }
)} )}
keyboardAppearance={mode} keyboardAppearance={mode}
@ -88,8 +88,8 @@ const ComposePoll: React.FC = () => {
}} }}
placeholder={ placeholder={
multiple multiple
? t('content.root.footer.poll.option.placeholder.multiple') ? t('screenCompose:content.root.footer.poll.option.placeholder.multiple')
: t('content.root.footer.poll.option.placeholder.single') : t('screenCompose:content.root.footer.poll.option.placeholder.single')
} }
placeholderTextColor={colors.disabled} placeholderTextColor={colors.disabled}
maxLength={MAX_CHARS_PER_OPTION} maxLength={MAX_CHARS_PER_OPTION}
@ -119,14 +119,15 @@ const ComposePoll: React.FC = () => {
{...(total > 2 {...(total > 2
? { ? {
accessibilityLabel: t( accessibilityLabel: t(
'content.root.footer.poll.quantity.reduce.accessibilityLabel', 'screenCompose:content.root.footer.poll.quantity.reduce.accessibilityLabel',
{ amount: total - 1 } { amount: total - 1 }
) )
} }
: { : {
accessibilityHint: t('content.root.footer.poll.quantity.reduce.accessibilityHint', { accessibilityHint: t(
amount: total 'screenCompose:content.root.footer.poll.quantity.reduce.accessibilityHint',
}) { amount: total }
)
})} })}
onPress={() => { onPress={() => {
total > 2 && total > 2 &&
@ -152,13 +153,13 @@ const ComposePoll: React.FC = () => {
{...(total < MAX_OPTIONS {...(total < MAX_OPTIONS
? { ? {
accessibilityLabel: t( accessibilityLabel: t(
'content.root.footer.poll.quantity.increase.accessibilityLabel', 'screenCompose:content.root.footer.poll.quantity.increase.accessibilityLabel',
{ amount: total + 1 } { amount: total + 1 }
) )
} }
: { : {
accessibilityHint: t( accessibilityHint: t(
'content.root.footer.poll.quantity.increase.accessibilityHint', 'screenCompose:content.root.footer.poll.quantity.increase.accessibilityHint',
{ amount: total } { amount: total }
) )
})} })}
@ -177,18 +178,18 @@ const ComposePoll: React.FC = () => {
</View> </View>
<View style={{ paddingHorizontal: StyleConstants.Spacing.Global.PagePadding }}> <View style={{ paddingHorizontal: StyleConstants.Spacing.Global.PagePadding }}>
<MenuRow <MenuRow
title={t('content.root.footer.poll.multiple.heading')} title={t('screenCompose:content.root.footer.poll.multiple.heading')}
content={ content={
multiple multiple
? t('content.root.footer.poll.multiple.options.multiple') ? t('screenCompose:content.root.footer.poll.multiple.options.multiple')
: t('content.root.footer.poll.multiple.options.single') : t('screenCompose:content.root.footer.poll.multiple.options.single')
} }
onPress={() => onPress={() =>
showActionSheetWithOptions( showActionSheetWithOptions(
{ {
options: [ options: [
t('content.root.footer.poll.multiple.options.single'), t('screenCompose:content.root.footer.poll.multiple.options.single'),
t('content.root.footer.poll.multiple.options.multiple'), t('screenCompose:content.root.footer.poll.multiple.options.multiple'),
t('common:buttons.cancel') t('common:buttons.cancel')
], ],
cancelButtonIndex: 2, cancelButtonIndex: 2,
@ -207,8 +208,8 @@ const ComposePoll: React.FC = () => {
iconBack='ChevronRight' iconBack='ChevronRight'
/> />
<MenuRow <MenuRow
title={t('content.root.footer.poll.expiration.heading')} title={t('screenCompose:content.root.footer.poll.expiration.heading')}
content={t(`content.root.footer.poll.expiration.options.${expire}`)} content={t(`screenCompose:content.root.footer.poll.expiration.options.${expire}`)}
onPress={() => { onPress={() => {
const expirations = [ const expirations = [
'300', '300',
@ -225,7 +226,9 @@ const ComposePoll: React.FC = () => {
showActionSheetWithOptions( showActionSheetWithOptions(
{ {
options: [ options: [
...expirations.map(e => t(`content.root.footer.poll.expiration.options.${e}`)), ...expirations.map(e =>
t(`screenCompose:content.root.footer.poll.expiration.options.${e}` as any)
),
t('common:buttons.cancel') t('common:buttons.cancel')
], ],
cancelButtonIndex: expirations.length, cancelButtonIndex: expirations.length,

View File

@ -41,7 +41,7 @@ const ScreenImagesViewer = ({
const insets = useSafeAreaInsets() const insets = useSafeAreaInsets()
const { mode, colors } = useTheme() const { mode, colors } = useTheme()
const { t } = useTranslation('screenImageViewer') const { t } = useTranslation(['common', 'screenImageViewer'])
const initialIndex = imageUrls.findIndex(image => image.id === id) const initialIndex = imageUrls.findIndex(image => image.id === id)
const [currentIndex, setCurrentIndex] = useState(initialIndex) const [currentIndex, setCurrentIndex] = useState(initialIndex)
@ -51,8 +51,8 @@ const ScreenImagesViewer = ({
showActionSheetWithOptions( showActionSheetWithOptions(
{ {
options: [ options: [
t('content.options.save'), t('screenImageViewer:content.options.save'),
t('content.options.share'), t('screenImageViewer:content.options.share'),
t('common:buttons.cancel') t('common:buttons.cancel')
], ],
cancelButtonIndex: 2, cancelButtonIndex: 2,
@ -164,8 +164,8 @@ const ScreenImagesViewer = ({
<HeaderCenter inverted content={`${currentIndex + 1} / ${imageUrls.length}`} /> <HeaderCenter inverted content={`${currentIndex + 1} / ${imageUrls.length}`} />
) : null} ) : null}
<HeaderRight <HeaderRight
accessibilityLabel={t('content.actions.accessibilityLabel')} accessibilityLabel={t('screenImageViewer:content.actions.accessibilityLabel')}
accessibilityHint={t('content.actions.accessibilityHint')} accessibilityHint={t('screenImageViewer:content.actions.accessibilityHint')}
content='MoreHorizontal' content='MoreHorizontal'
native={false} native={false}
background background
@ -177,8 +177,8 @@ const ScreenImagesViewer = ({
showActionSheetWithOptions( showActionSheetWithOptions(
{ {
options: [ options: [
t('content.options.save'), t('screenImageViewer:content.options.save'),
t('content.options.share'), t('screenImageViewer:content.options.share'),
t('common:buttons.cancel') t('common:buttons.cancel')
], ],
cancelButtonIndex: 2, cancelButtonIndex: 2,

View File

@ -12,7 +12,7 @@ import { FlatList } from 'react-native-gesture-handler'
const TabMeFollowedTags: React.FC<TabMeStackScreenProps<'Tab-Me-FollowedTags'>> = ({ const TabMeFollowedTags: React.FC<TabMeStackScreenProps<'Tab-Me-FollowedTags'>> = ({
navigation navigation
}) => { }) => {
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common', 'screenTabs'])
const { data, fetchNextPage, refetch } = useFollowedTagsQuery() const { data, fetchNextPage, refetch } = useFollowedTagsQuery()
const flattenData = data?.pages ? data.pages.flatMap(page => [...page.body]) : [] const flattenData = data?.pages ? data.pages.flatMap(page => [...page.body]) : []
@ -31,7 +31,9 @@ const TabMeFollowedTags: React.FC<TabMeStackScreenProps<'Tab-Me-FollowedTags'>>
displayMessage({ displayMessage({
type: 'error', type: 'error',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: to ? t('shared.hashtag.follow') : t('shared.hashtag.unfollow') function: to
? t('screenTabs:shared.hashtag.follow')
: t('screenTabs:shared.hashtag.unfollow')
}), }),
...(err.status && ...(err.status &&
typeof err.status === 'number' && typeof err.status === 'number' &&
@ -55,7 +57,7 @@ const TabMeFollowedTags: React.FC<TabMeStackScreenProps<'Tab-Me-FollowedTags'>>
children={ children={
<Button <Button
type='text' type='text'
content={t('shared.hashtag.unfollow')} content={t('screenTabs:shared.hashtag.unfollow')}
onPress={() => mutation.mutate({ tag: item.name, to: !item.following })} onPress={() => mutation.mutate({ tag: item.name, to: !item.following })}
/> />
} }

View File

@ -19,7 +19,7 @@ const TabMeListAccounts: React.FC<TabMeStackScreenProps<'Tab-Me-List-Accounts'>>
route: { params } route: { params }
}) => { }) => {
const { colors, theme } = useTheme() const { colors, theme } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common', 'screenTabs'])
const queryKey: QueryKeyListAccounts = ['ListAccounts', { id: params.id }] const queryKey: QueryKeyListAccounts = ['ListAccounts', { id: params.id }]
const { data, refetch, fetchNextPage, hasNextPage } = useListAccountsQuery({ const { data, refetch, fetchNextPage, hasNextPage } = useListAccountsQuery({
@ -45,7 +45,7 @@ const TabMeListAccounts: React.FC<TabMeStackScreenProps<'Tab-Me-List-Accounts'>>
displayMessage({ displayMessage({
type: 'danger', type: 'danger',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t('me.listAccounts.error') function: t('screenTabs:me.listAccounts.error')
}) })
}) })
} }
@ -88,7 +88,7 @@ const TabMeListAccounts: React.FC<TabMeStackScreenProps<'Tab-Me-List-Accounts'>>
color: colors.secondary color: colors.secondary
}} }}
> >
{t('me.listAccounts.empty')} {t('screenTabs:me.listAccounts.empty')}
</CustomText> </CustomText>
</View> </View>
} }

View File

@ -20,7 +20,7 @@ const TabMeListEdit: React.FC<TabMeStackScreenProps<'Tab-Me-List-Edit'>> = ({
route: { params } route: { params }
}) => { }) => {
const { colors, theme } = useTheme() const { colors, theme } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common', 'screenTabs'])
const messageRef = useRef(null) const messageRef = useRef(null)
@ -44,7 +44,9 @@ const TabMeListEdit: React.FC<TabMeStackScreenProps<'Tab-Me-List-Edit'>> = ({
type: 'danger', type: 'danger',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: function:
params.type === 'add' ? t('me.stacks.listAdd.name') : t('me.stacks.listEdit.name') params.type === 'add'
? t('screenTabs:me.stacks.listAdd.name')
: t('screenTabs:me.stacks.listEdit.name')
}) })
}) })
} }
@ -65,24 +67,27 @@ const TabMeListEdit: React.FC<TabMeStackScreenProps<'Tab-Me-List-Edit'>> = ({
>([ >([
{ {
id: 'none', id: 'none',
content: t('me.listEdit.repliesPolicy.options.none'), content: t('screenTabs:me.listEdit.repliesPolicy.options.none'),
selected: params.type === 'edit' ? params.payload.replies_policy === 'none' : false selected: params.type === 'edit' ? params.payload.replies_policy === 'none' : false
}, },
{ {
id: 'list', id: 'list',
content: t('me.listEdit.repliesPolicy.options.list'), content: t('screenTabs:me.listEdit.repliesPolicy.options.list'),
selected: params.type === 'edit' ? params.payload.replies_policy === 'list' : true selected: params.type === 'edit' ? params.payload.replies_policy === 'list' : true
}, },
{ {
id: 'followed', id: 'followed',
content: t('me.listEdit.repliesPolicy.options.followed'), content: t('screenTabs:me.listEdit.repliesPolicy.options.followed'),
selected: params.type === 'edit' ? params.payload.replies_policy === 'followed' : false selected: params.type === 'edit' ? params.payload.replies_policy === 'followed' : false
} }
]) ])
useEffect(() => { useEffect(() => {
navigation.setOptions({ navigation.setOptions({
title: params.type === 'add' ? t('me.stacks.listAdd.name') : t('me.stacks.listEdit.name'), title:
params.type === 'add'
? t('screenTabs:me.stacks.listAdd.name')
: t('screenTabs:me.stacks.listEdit.name'),
headerLeft: () => ( headerLeft: () => (
<HeaderLeft <HeaderLeft
content='X' content='X'
@ -140,7 +145,7 @@ const TabMeListEdit: React.FC<TabMeStackScreenProps<'Tab-Me-List-Edit'>> = ({
return ( return (
<ScrollView style={{ paddingHorizontal: StyleConstants.Spacing.Global.PagePadding }}> <ScrollView style={{ paddingHorizontal: StyleConstants.Spacing.Global.PagePadding }}>
<ComponentInput {...inputProps} autoFocus title={t('me.listEdit.title')} /> <ComponentInput {...inputProps} autoFocus title={t('screenTabs:me.listEdit.title')} />
<CustomText <CustomText
fontStyle='M' fontStyle='M'
@ -151,7 +156,7 @@ const TabMeListEdit: React.FC<TabMeStackScreenProps<'Tab-Me-List-Edit'>> = ({
marginTop: StyleConstants.Spacing.M marginTop: StyleConstants.Spacing.M
}} }}
> >
{t('me.listEdit.repliesPolicy.heading')} {t('screenTabs:me.listEdit.repliesPolicy.heading')}
</CustomText> </CustomText>
<Selections options={options} setOptions={setOptions} /> <Selections options={options} setOptions={setOptions} />

View File

@ -14,7 +14,7 @@ const TabMeListList: React.FC<TabMeStackScreenProps<'Tab-Me-List-List'>> = ({ na
headerRight: () => ( headerRight: () => (
<HeaderRight <HeaderRight
type='text' type='text'
content={t('common:buttons.create')} content={t('buttons.create')}
onPress={() => navigation.navigate('Tab-Me-List-Edit', { type: 'add' })} onPress={() => navigation.navigate('Tab-Me-List-Edit', { type: 'add' })}
/> />
) )

View File

@ -18,7 +18,7 @@ const TabMeList: React.FC<TabMeStackScreenProps<'Tab-Me-List'>> = ({
route: { key, params } route: { key, params }
}) => { }) => {
const { colors } = useTheme() const { colors } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common', 'screenTabs'])
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'List', list: params.id }] const queryKey: QueryKeyTimeline = ['Timeline', { page: 'List', list: params.id }]
const queryKeyLists: QueryKeyLists = ['Lists'] const queryKeyLists: QueryKeyLists = ['Lists']
@ -32,7 +32,7 @@ const TabMeList: React.FC<TabMeStackScreenProps<'Tab-Me-List'>> = ({
displayMessage({ displayMessage({
type: 'danger', type: 'danger',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: t('me.listDelete.heading') function: t('screenTabs:me.listDelete.heading')
}) })
}) })
} }

View File

@ -19,7 +19,7 @@ const Field: React.FC<{
field?: Mastodon.Field field?: Mastodon.Field
}> = ({ allProps, setDirty, index, field }) => { }> = ({ allProps, setDirty, index, field }) => {
const { colors } = useTheme() const { colors } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common', 'screenTabs'])
const nameRef = useRef<TextInput>(null) const nameRef = useRef<TextInput>(null)
const valueRef = useRef<TextInput>(null) const valueRef = useRef<TextInput>(null)
@ -55,11 +55,11 @@ const Field: React.FC<{
color: colors.primaryDefault color: colors.primaryDefault
}} }}
> >
{t('me.profile.fields.group', { index: index + 1 })} {t('screenTabs:me.profile.fields.group', { index: index + 1 })}
</CustomText> </CustomText>
<ComponentInput title={t('me.profile.fields.label')} {...allProps[index * 2]} /> <ComponentInput title={t('screenTabs:me.profile.fields.label')} {...allProps[index * 2]} />
<ComponentInput <ComponentInput
title={t('me.profile.fields.content')} title={t('screenTabs:me.profile.fields.content')}
{...allProps[index * 2 + 1]} {...allProps[index * 2 + 1]}
multiline multiline
/> />
@ -79,7 +79,7 @@ const TabMeProfileFields: React.FC<
navigation navigation
}) => { }) => {
const { theme } = useTheme() const { theme } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common'])
const { mutateAsync, status } = useProfileMutation() const { mutateAsync, status } = useProfileMutation()
const allProps: EmojisState['inputProps'] = [] const allProps: EmojisState['inputProps'] = []
@ -93,21 +93,17 @@ const TabMeProfileFields: React.FC<
content='X' content='X'
onPress={() => { onPress={() => {
if (dirty) { if (dirty) {
Alert.alert( Alert.alert(t('common:discard.title'), t('common:discard.message'), [
t('common:discard.title'), {
t('common:discard.message'), text: t('common:buttons.discard'),
[ style: 'destructive',
{ onPress: () => navigation.navigate('Tab-Me-Profile-Root')
text: t('common:buttons.discard'), },
style: 'destructive', {
onPress: () => navigation.navigate('Tab-Me-Profile-Root') text: t('common:buttons.cancel'),
}, style: 'default'
{ }
text: t('common:buttons.cancel'), ])
style: 'default'
}
]
)
} else { } else {
navigation.navigate('Tab-Me-Profile-Root') navigation.navigate('Tab-Me-Profile-Root')
} }

View File

@ -23,7 +23,7 @@ const TabMeProfileName: React.FC<
navigation navigation
}) => { }) => {
const { theme } = useTheme() const { theme } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common'])
const { mutateAsync, status } = useProfileMutation() const { mutateAsync, status } = useProfileMutation()
const [value, setValue] = useState(display_name) const [value, setValue] = useState(display_name)
@ -47,21 +47,17 @@ const TabMeProfileName: React.FC<
content='X' content='X'
onPress={() => { onPress={() => {
if (dirty) { if (dirty) {
Alert.alert( Alert.alert(t('common:discard.title'), t('common:discard.message'), [
t('common:discard.title'), {
t('common:discard.message'), text: t('common:buttons.discard'),
[ style: 'destructive',
{ onPress: () => navigation.navigate('Tab-Me-Profile-Root')
text: t('common:buttons.discard'), },
style: 'destructive', {
onPress: () => navigation.navigate('Tab-Me-Profile-Root') text: t('common:buttons.cancel'),
}, style: 'default'
{ }
text: t('common:buttons.cancel'), ])
style: 'default'
}
]
)
} else { } else {
navigation.navigate('Tab-Me-Profile-Root') navigation.navigate('Tab-Me-Profile-Root')
} }

View File

@ -23,7 +23,7 @@ const TabMeProfileNote: React.FC<
navigation navigation
}) => { }) => {
const { theme } = useTheme() const { theme } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common'])
const { mutateAsync, status } = useProfileMutation() const { mutateAsync, status } = useProfileMutation()
const [notes, setNotes] = useState(note) const [notes, setNotes] = useState(note)
@ -47,21 +47,17 @@ const TabMeProfileNote: React.FC<
content='X' content='X'
onPress={() => { onPress={() => {
if (dirty) { if (dirty) {
Alert.alert( Alert.alert(t('common:discard.title'), t('common:discard.message'), [
t('common:discard.title'), {
t('common:discard.message'), text: t('common:buttons.discard'),
[ style: 'destructive',
{ onPress: () => navigation.navigate('Tab-Me-Profile-Root')
text: t('common:buttons.discard'), },
style: 'destructive', {
onPress: () => navigation.navigate('Tab-Me-Profile-Root') text: t('common:buttons.cancel'),
}, style: 'default'
{ }
text: t('common:buttons.cancel'), ])
style: 'default'
}
]
)
} else { } else {
navigation.navigate('Tab-Me-Profile-Root') navigation.navigate('Tab-Me-Profile-Root')
} }

View File

@ -18,7 +18,7 @@ const TabMeProfileRoot: React.FC<
} }
> = ({ messageRef, navigation }) => { > = ({ messageRef, navigation }) => {
const { colors } = useTheme() const { colors } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common', 'screenTabs'])
const { showActionSheetWithOptions } = useActionSheet() const { showActionSheetWithOptions } = useActionSheet()
@ -30,7 +30,7 @@ const TabMeProfileRoot: React.FC<
<ScrollView> <ScrollView>
<MenuContainer> <MenuContainer>
<MenuRow <MenuRow
title={t('me.profile.root.name.title')} title={t('screenTabs:me.profile.root.name.title')}
content={data?.display_name} content={data?.display_name}
loading={isFetching} loading={isFetching}
iconBack='ChevronRight' iconBack='ChevronRight'
@ -44,7 +44,7 @@ const TabMeProfileRoot: React.FC<
<ProfileAvatarHeader type='avatar' messageRef={messageRef} /> <ProfileAvatarHeader type='avatar' messageRef={messageRef} />
<ProfileAvatarHeader type='header' messageRef={messageRef} /> <ProfileAvatarHeader type='header' messageRef={messageRef} />
<MenuRow <MenuRow
title={t('me.profile.root.note.title')} title={t('screenTabs:me.profile.root.note.title')}
content={data?.source.note} content={data?.source.note}
loading={isFetching} loading={isFetching}
iconBack='ChevronRight' iconBack='ChevronRight'
@ -56,10 +56,10 @@ const TabMeProfileRoot: React.FC<
}} }}
/> />
<MenuRow <MenuRow
title={t('me.profile.root.fields.title')} title={t('screenTabs:me.profile.root.fields.title')}
content={ content={
data?.source.fields && data.source.fields.length data?.source.fields && data.source.fields.length
? t('me.profile.root.fields.total', { ? t('screenTabs:me.profile.root.fields.total', {
count: data.source.fields.length count: data.source.fields.length
}) })
: undefined : undefined
@ -74,58 +74,60 @@ const TabMeProfileRoot: React.FC<
/> />
</MenuContainer> </MenuContainer>
<MenuContainer> <MenuContainer>
<MenuRow {data?.source.privacy !== 'direct' ? (
title={t('me.profile.root.visibility.title')} <MenuRow
content={ title={t('screenTabs:me.profile.root.visibility.title')}
data?.source.privacy content={
? t(`me.profile.root.visibility.options.${data?.source.privacy}`) data?.source.privacy
: undefined ? t(`screenTabs:me.profile.root.visibility.options.${data.source.privacy}`)
} : undefined
loading={isFetching} }
iconBack='ChevronRight' loading={isFetching}
onPress={() => iconBack='ChevronRight'
showActionSheetWithOptions( onPress={() =>
{ showActionSheetWithOptions(
title: t('me.profile.root.visibility.title'), {
options: [ title: t('screenTabs:me.profile.root.visibility.title'),
t('me.profile.root.visibility.options.public'), options: [
t('me.profile.root.visibility.options.unlisted'), t('screenTabs:me.profile.root.visibility.options.public'),
t('me.profile.root.visibility.options.private'), t('screenTabs:me.profile.root.visibility.options.unlisted'),
t('common:buttons.cancel') t('screenTabs:me.profile.root.visibility.options.private'),
], t('common:buttons.cancel')
cancelButtonIndex: 3, ],
...androidActionSheetStyles(colors) cancelButtonIndex: 3,
}, ...androidActionSheetStyles(colors)
async buttonIndex => { },
switch (buttonIndex) { async buttonIndex => {
case 0: switch (buttonIndex) {
case 1: case 0:
case 2: case 1:
const indexVisibilityMapping = ['public', 'unlisted', 'private'] as [ case 2:
'public', const indexVisibilityMapping = ['public', 'unlisted', 'private'] as [
'unlisted', 'public',
'private' 'unlisted',
] 'private'
if (data?.source.privacy !== indexVisibilityMapping[buttonIndex]) { ]
mutateAsync({ if (data?.source.privacy !== indexVisibilityMapping[buttonIndex]) {
messageRef, mutateAsync({
message: { messageRef,
text: 'me.profile.root.visibility.title', message: {
succeed: false, text: 'me.profile.root.visibility.title',
failed: true succeed: false,
}, failed: true
type: 'source[privacy]', },
data: indexVisibilityMapping[buttonIndex] type: 'source[privacy]',
}).then(() => dispatch(updateAccountPreferences())) data: indexVisibilityMapping[buttonIndex]
} }).then(() => dispatch(updateAccountPreferences()))
break }
break
}
} }
} )
) }
} />
/> ) : null}
<MenuRow <MenuRow
title={t('me.profile.root.sensitive.title')} title={t('screenTabs:me.profile.root.sensitive.title')}
switchValue={data?.source.sensitive} switchValue={data?.source.sensitive}
switchOnValueChange={() => switchOnValueChange={() =>
mutateAsync({ mutateAsync({
@ -144,8 +146,8 @@ const TabMeProfileRoot: React.FC<
</MenuContainer> </MenuContainer>
<MenuContainer> <MenuContainer>
<MenuRow <MenuRow
title={t('me.profile.root.lock.title')} title={t('screenTabs:me.profile.root.lock.title')}
description={t('me.profile.root.lock.description')} description={t('screenTabs:me.profile.root.lock.description')}
switchValue={data?.locked} switchValue={data?.locked}
switchOnValueChange={() => switchOnValueChange={() =>
mutateAsync({ mutateAsync({
@ -162,8 +164,8 @@ const TabMeProfileRoot: React.FC<
loading={isFetching} loading={isFetching}
/> />
<MenuRow <MenuRow
title={t('me.profile.root.bot.title')} title={t('screenTabs:me.profile.root.bot.title')}
description={t('me.profile.root.bot.description')} description={t('screenTabs:me.profile.root.bot.description')}
switchValue={data?.bot} switchValue={data?.bot}
switchOnValueChange={() => switchOnValueChange={() =>
mutateAsync({ mutateAsync({

View File

@ -13,7 +13,7 @@ export interface Props {
} }
const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => { const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => {
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['screenTabs'])
const { showActionSheetWithOptions } = useActionSheet() const { showActionSheetWithOptions } = useActionSheet()
@ -22,8 +22,8 @@ const ProfileAvatarHeader: React.FC<Props> = ({ type, messageRef }) => {
return ( return (
<MenuRow <MenuRow
title={t(`me.profile.root.${type}.title`)} title={t(`screenTabs:me.profile.root.${type}.title`)}
description={t(`me.profile.root.${type}.description`)} description={t(`screenTabs:me.profile.root.${type}.description`)}
loading={query.isFetching || mutation.isLoading} loading={query.isFetching || mutation.isLoading}
iconBack='ChevronRight' iconBack='ChevronRight'
onPress={async () => { onPress={async () => {

View File

@ -10,12 +10,12 @@ import {
updateInstanceMePage updateInstanceMePage
} from '@utils/slices/instancesSlice' } from '@utils/slices/instancesSlice'
import { getInstancePush } from '@utils/slices/instancesSlice' import { getInstancePush } from '@utils/slices/instancesSlice'
import React, { useEffect } from 'react' import React from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
const Collections: React.FC = () => { const Collections: React.FC = () => {
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['screenAnnouncements', 'screenTabs'])
const navigation = useNavigation<any>() const navigation = useNavigation<any>()
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
@ -65,26 +65,26 @@ const Collections: React.FC = () => {
<MenuRow <MenuRow
iconFront='Mail' iconFront='Mail'
iconBack='ChevronRight' iconBack='ChevronRight'
title={t('me.stacks.conversations.name')} title={t('screenTabs:me.stacks.conversations.name')}
onPress={() => navigation.navigate('Tab-Me-Conversations')} onPress={() => navigation.navigate('Tab-Me-Conversations')}
/> />
<MenuRow <MenuRow
iconFront='Bookmark' iconFront='Bookmark'
iconBack='ChevronRight' iconBack='ChevronRight'
title={t('me.stacks.bookmarks.name')} title={t('screenTabs:me.stacks.bookmarks.name')}
onPress={() => navigation.navigate('Tab-Me-Bookmarks')} onPress={() => navigation.navigate('Tab-Me-Bookmarks')}
/> />
<MenuRow <MenuRow
iconFront='Heart' iconFront='Heart'
iconBack='ChevronRight' iconBack='ChevronRight'
title={t('me.stacks.favourites.name')} title={t('screenTabs:me.stacks.favourites.name')}
onPress={() => navigation.navigate('Tab-Me-Favourites')} onPress={() => navigation.navigate('Tab-Me-Favourites')}
/> />
{mePage.lists.shown ? ( {mePage.lists.shown ? (
<MenuRow <MenuRow
iconFront='List' iconFront='List'
iconBack='ChevronRight' iconBack='ChevronRight'
title={t('me.stacks.lists.name')} title={t('screenTabs:me.stacks.lists.name')}
onPress={() => navigation.navigate('Tab-Me-List-List')} onPress={() => navigation.navigate('Tab-Me-List-List')}
/> />
) : null} ) : null}
@ -92,7 +92,7 @@ const Collections: React.FC = () => {
<MenuRow <MenuRow
iconFront='Hash' iconFront='Hash'
iconBack='ChevronRight' iconBack='ChevronRight'
title={t('me.stacks.followedTags.name')} title={t('screenTabs:me.stacks.followedTags.name')}
onPress={() => navigation.navigate('Tab-Me-FollowedTags')} onPress={() => navigation.navigate('Tab-Me-FollowedTags')}
/> />
) : null} ) : null}
@ -103,10 +103,10 @@ const Collections: React.FC = () => {
title={t('screenAnnouncements:heading')} title={t('screenAnnouncements:heading')}
content={ content={
mePage.announcements.unread mePage.announcements.unread
? t('me.root.announcements.content.unread', { ? t('screenTabs:me.root.announcements.content.unread', {
amount: mePage.announcements.unread amount: mePage.announcements.unread
}) })
: t('me.root.announcements.content.read') : t('screenTabs:me.root.announcements.content.read')
} }
onPress={() => navigation.navigate('Screen-Announcements', { showAll: true })} onPress={() => navigation.navigate('Screen-Announcements', { showAll: true })}
/> />
@ -114,10 +114,13 @@ const Collections: React.FC = () => {
<MenuRow <MenuRow
iconFront={instancePush ? 'Bell' : 'BellOff'} iconFront={instancePush ? 'Bell' : 'BellOff'}
iconBack='ChevronRight' iconBack='ChevronRight'
title={t('me.stacks.push.name')} title={t('screenTabs:me.stacks.push.name')}
content={ content={
typeof instancePush.global === 'boolean' typeof instancePush.global === 'boolean'
? t('me.root.push.content', { context: instancePush.global.toString() }) ? t('screenTabs:me.root.push.content', {
defaultValue: 'false',
context: instancePush.global.toString()
})
: undefined : undefined
} }
onPress={() => navigation.navigate('Tab-Me-Push')} onPress={() => navigation.navigate('Tab-Me-Push')}

View File

@ -11,7 +11,7 @@ import { useQueryClient } from '@tanstack/react-query'
import { useSelector } from 'react-redux' import { useSelector } from 'react-redux'
const Logout: React.FC = () => { const Logout: React.FC = () => {
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common', 'screenTabs'])
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const instance = useSelector(getInstance) const instance = useSelector(getInstance)
@ -19,7 +19,7 @@ const Logout: React.FC = () => {
return ( return (
<Button <Button
type='text' type='text'
content={t('me.root.logout.button')} content={t('screenTabs:me.root.logout.button')}
style={{ style={{
marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2, marginHorizontal: StyleConstants.Spacing.Global.PagePadding * 2,
marginTop: StyleConstants.Spacing.Global.PagePadding, marginTop: StyleConstants.Spacing.Global.PagePadding,
@ -27,23 +27,27 @@ const Logout: React.FC = () => {
}} }}
destructive destructive
onPress={() => onPress={() =>
Alert.alert(t('me.root.logout.alert.title'), t('me.root.logout.alert.message'), [ Alert.alert(
{ t('screenTabs:me.root.logout.alert.title'),
text: t('me.root.logout.alert.buttons.logout'), t('screenTabs:me.root.logout.alert.message'),
style: 'destructive', [
onPress: () => { {
if (instance) { text: t('screenTabs:me.root.logout.alert.buttons.logout'),
haptics('Success') style: 'destructive',
queryClient.clear() onPress: () => {
dispatch(removeInstance(instance)) if (instance) {
haptics('Success')
queryClient.clear()
dispatch(removeInstance(instance))
}
} }
},
{
text: t('common:buttons.cancel'),
style: 'default'
} }
}, ]
{ )
text: t('common:buttons.cancel'),
style: 'default'
}
])
} }
/> />
) )

View File

@ -29,7 +29,7 @@ const SettingsApp: React.FC = () => {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
const { showActionSheetWithOptions } = useActionSheet() const { showActionSheetWithOptions } = useActionSheet()
const { colors } = useTheme() const { colors } = useTheme()
const { t, i18n } = useTranslation('screenTabs') const { t, i18n } = useTranslation(['common', 'screenTabs'])
const settingsFontsize = useSelector(getSettingsFontsize) const settingsFontsize = useSelector(getSettingsFontsize)
const settingsTheme = useSelector(getSettingsTheme) const settingsTheme = useSelector(getSettingsTheme)
@ -40,13 +40,15 @@ const SettingsApp: React.FC = () => {
return ( return (
<MenuContainer> <MenuContainer>
<MenuRow <MenuRow
title={t('me.settings.fontsize.heading')} title={t('screenTabs:me.settings.fontsize.heading')}
content={t(`me.settings.fontsize.content.${mapFontsizeToName(settingsFontsize)}`)} content={t(
`screenTabs:me.settings.fontsize.content.${mapFontsizeToName(settingsFontsize)}`
)}
iconBack='ChevronRight' iconBack='ChevronRight'
onPress={() => navigation.navigate('Tab-Me-Settings-Fontsize')} onPress={() => navigation.navigate('Tab-Me-Settings-Fontsize')}
/> />
<MenuRow <MenuRow
title={t('me.settings.language.heading')} title={t('screenTabs:me.settings.language.heading')}
content={ content={
// @ts-ignore // @ts-ignore
LOCALES[ LOCALES[
@ -61,17 +63,17 @@ const SettingsApp: React.FC = () => {
} }
/> />
<MenuRow <MenuRow
title={t('me.settings.theme.heading')} title={t('screenTabs:me.settings.theme.heading')}
content={t(`me.settings.theme.options.${settingsTheme}`)} content={t(`screenTabs:me.settings.theme.options.${settingsTheme}`)}
iconBack='ChevronRight' iconBack='ChevronRight'
onPress={() => onPress={() =>
showActionSheetWithOptions( showActionSheetWithOptions(
{ {
title: t('me.settings.theme.heading'), title: t('screenTabs:me.settings.theme.heading'),
options: [ options: [
t('me.settings.theme.options.auto'), t('screenTabs:me.settings.theme.options.auto'),
t('me.settings.theme.options.light'), t('screenTabs:me.settings.theme.options.light'),
t('me.settings.theme.options.dark'), t('screenTabs:me.settings.theme.options.dark'),
t('common:buttons.cancel') t('common:buttons.cancel')
], ],
cancelButtonIndex: 3, cancelButtonIndex: 3,
@ -97,16 +99,16 @@ const SettingsApp: React.FC = () => {
} }
/> />
<MenuRow <MenuRow
title={t('me.settings.darkTheme.heading')} title={t('screenTabs:me.settings.darkTheme.heading')}
content={t(`me.settings.darkTheme.options.${settingsDarkTheme}`)} content={t(`screenTabs:me.settings.darkTheme.options.${settingsDarkTheme}`)}
iconBack='ChevronRight' iconBack='ChevronRight'
onPress={() => onPress={() =>
showActionSheetWithOptions( showActionSheetWithOptions(
{ {
title: t('me.settings.darkTheme.heading'), title: t('screenTabs:me.settings.darkTheme.heading'),
options: [ options: [
t('me.settings.darkTheme.options.lighter'), t('screenTabs:me.settings.darkTheme.options.lighter'),
t('me.settings.darkTheme.options.darker'), t('screenTabs:me.settings.darkTheme.options.darker'),
t('common:buttons.cancel') t('common:buttons.cancel')
], ],
cancelButtonIndex: 2, cancelButtonIndex: 2,
@ -128,16 +130,16 @@ const SettingsApp: React.FC = () => {
} }
/> />
<MenuRow <MenuRow
title={t('me.settings.browser.heading')} title={t('screenTabs:me.settings.browser.heading')}
content={t(`me.settings.browser.options.${settingsBrowser}`)} content={t(`screenTabs:me.settings.browser.options.${settingsBrowser}`)}
iconBack='ChevronRight' iconBack='ChevronRight'
onPress={() => onPress={() =>
showActionSheetWithOptions( showActionSheetWithOptions(
{ {
title: t('me.settings.browser.heading'), title: t('screenTabs:me.settings.browser.heading'),
options: [ options: [
t('me.settings.browser.options.internal'), t('screenTabs:me.settings.browser.options.internal'),
t('me.settings.browser.options.external'), t('screenTabs:me.settings.browser.options.external'),
t('common:buttons.cancel') t('common:buttons.cancel')
], ],
cancelButtonIndex: 2, cancelButtonIndex: 2,
@ -159,8 +161,8 @@ const SettingsApp: React.FC = () => {
} }
/> />
<MenuRow <MenuRow
title={t('me.settings.staticEmoji.heading')} title={t('screenTabs:me.settings.staticEmoji.heading')}
description={t('me.settings.staticEmoji.description')} description={t('screenTabs:me.settings.staticEmoji.description')}
switchValue={settingsStaticEmoji} switchValue={settingsStaticEmoji}
switchOnValueChange={() => dispatch(changeStaticEmoji(!settingsStaticEmoji))} switchOnValueChange={() => dispatch(changeStaticEmoji(!settingsStaticEmoji))}
/> />

View File

@ -20,7 +20,7 @@ import { useSelector } from 'react-redux'
const TabNotificationsFilters: React.FC< const TabNotificationsFilters: React.FC<
TabNotificationsStackScreenProps<'Tab-Notifications-Filters'> TabNotificationsStackScreenProps<'Tab-Notifications-Filters'>
> = ({ navigation }) => { > = ({ navigation }) => {
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common', 'screenTabs'])
const pushFeatures = usePushFeatures() const pushFeatures = usePushFeatures()
@ -33,7 +33,7 @@ const TabNotificationsFilters: React.FC<
useEffect(() => { useEffect(() => {
const changed = !isEqual(instanceNotificationsFilter, filters) const changed = !isEqual(instanceNotificationsFilter, filters)
navigation.setOptions({ navigation.setOptions({
title: t('notifications.filters.title'), title: t('screenTabs:notifications.filters.title'),
headerLeft: () => ( headerLeft: () => (
<HeaderLeft <HeaderLeft
content='ChevronDown' content='ChevronDown'
@ -81,7 +81,7 @@ const TabNotificationsFilters: React.FC<
{PUSH_DEFAULT(pushFeatures).map((type, index) => ( {PUSH_DEFAULT(pushFeatures).map((type, index) => (
<MenuRow <MenuRow
key={index} key={index}
title={t(`notifications.filters.options.${type}`)} title={t(`screenTabs:notifications.filters.options.${type}`)}
switchValue={filters[type]} switchValue={filters[type]}
switchOnValueChange={() => setFilters({ ...filters, [type]: !filters[type] })} switchOnValueChange={() => setFilters({ ...filters, [type]: !filters[type] })}
/> />
@ -89,7 +89,7 @@ const TabNotificationsFilters: React.FC<
{PUSH_ADMIN(pushFeatures, profileQuery.data?.role?.permissions).map(({ type }) => ( {PUSH_ADMIN(pushFeatures, profileQuery.data?.role?.permissions).map(({ type }) => (
<MenuRow <MenuRow
key={type} key={type}
title={t(`notifications.filters.options.${type}`)} title={t(`screenTabs:notifications.filters.options.${type}`)}
switchValue={filters[type]} switchValue={filters[type]}
switchOnValueChange={() => setFilters({ ...filters, [type]: !filters[type] })} switchOnValueChange={() => setFilters({ ...filters, [type]: !filters[type] })}
/> />

View File

@ -21,12 +21,12 @@ const TabSharedAccountInLists: React.FC<
} }
}) => { }) => {
const { colors } = useTheme() const { colors } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common', 'screenTabs'])
useEffect(() => { useEffect(() => {
navigation.setOptions({ navigation.setOptions({
presentation: 'modal', presentation: 'modal',
title: t('shared.accountInLists.name', { username: account.username }), title: t('screenTabs:shared.accountInLists.name', { username: account.username }),
headerRight: () => { headerRight: () => {
return ( return (
<HeaderRight <HeaderRight
@ -43,10 +43,14 @@ const TabSharedAccountInLists: React.FC<
const accountInListsQuery = useAccountInListsQuery({ id: account.id }) const accountInListsQuery = useAccountInListsQuery({ id: account.id })
const sections = [ const sections = [
{ id: 'in', title: t('shared.accountInLists.inLists'), data: accountInListsQuery.data || [] }, {
id: 'in',
title: t('screenTabs:shared.accountInLists.inLists'),
data: accountInListsQuery.data || []
},
{ {
id: 'out', id: 'out',
title: t('shared.accountInLists.notInLists'), title: t('screenTabs:shared.accountInLists.notInLists'),
data: data:
listsQuery.data?.filter(({ id }) => listsQuery.data?.filter(({ id }) =>
accountInListsQuery.data?.length accountInListsQuery.data?.length

View File

@ -23,7 +23,8 @@ const TabSharedAttachments: React.FC<TabSharedStackScreenProps<'Tab-Shared-Attac
headerTitle: () => ( headerTitle: () => (
<CustomText numberOfLines={1}> <CustomText numberOfLines={1}>
<Trans <Trans
i18nKey='screenTabs:shared.attachments.name' ns='screenTabs'
i18nKey='shared.attachments.name'
components={[ components={[
<ParseEmojis <ParseEmojis
content={account.display_name || account.username} content={account.display_name || account.username}

View File

@ -27,7 +27,7 @@ const TabSharedHashtag: React.FC<TabSharedStackScreenProps<'Tab-Shared-Hashtag'>
const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Hashtag', hashtag }] const queryKey: QueryKeyTimeline = ['Timeline', { page: 'Hashtag', hashtag }]
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common', 'screenTabs'])
const canFollowTags = useSelector(checkInstanceFeature('follow_tags')) const canFollowTags = useSelector(checkInstanceFeature('follow_tags'))
const { data, isFetching, refetch } = useTagsQuery({ const { data, isFetching, refetch } = useTagsQuery({
@ -46,7 +46,9 @@ const TabSharedHashtag: React.FC<TabSharedStackScreenProps<'Tab-Shared-Hashtag'>
displayMessage({ displayMessage({
type: 'error', type: 'error',
message: t('common:message.error.message', { message: t('common:message.error.message', {
function: to ? t('shared.hashtag.follow') : t('shared.hashtag.unfollow') function: to
? t('screenTabs:shared.hashtag.follow')
: t('screenTabs:shared.hashtag.unfollow')
}), }),
...(err.status && ...(err.status &&
typeof err.status === 'number' && typeof err.status === 'number' &&
@ -66,7 +68,11 @@ const TabSharedHashtag: React.FC<TabSharedStackScreenProps<'Tab-Shared-Hashtag'>
<HeaderRight <HeaderRight
loading={isFetching || mutation.isLoading} loading={isFetching || mutation.isLoading}
type='text' type='text'
content={data?.following ? t('shared.hashtag.unfollow') : t('shared.hashtag.follow')} content={
data?.following
? t('screenTabs:shared.hashtag.unfollow')
: t('screenTabs:shared.hashtag.follow')
}
onPress={() => onPress={() =>
typeof data?.following === 'boolean' && typeof data?.following === 'boolean' &&
mutation.mutate({ tag: hashtag, to: !data.following }) mutation.mutate({ tag: hashtag, to: !data.following })

View File

@ -21,14 +21,14 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
} }
}) => { }) => {
const { colors } = useTheme() const { colors } = useTheme()
const { t } = useTranslation('screenTabs') const { t } = useTranslation(['common', 'screenTabs'])
const [categories, setCategories] = useState< const [categories, setCategories] = useState<
{ selected: boolean; content: string; type: 'spam' | 'other' | 'violation' }[] { selected: boolean; content: string; type: 'spam' | 'other' | 'violation' }[]
>([ >([
{ selected: true, content: t('shared.report.reasons.spam'), type: 'spam' }, { selected: true, content: t('screenTabs:shared.report.reasons.spam'), type: 'spam' },
{ selected: false, content: t('shared.report.reasons.other'), type: 'other' }, { selected: false, content: t('screenTabs:shared.report.reasons.other'), type: 'other' },
{ selected: false, content: t('shared.report.reasons.violation'), type: 'violation' } { selected: false, content: t('screenTabs:shared.report.reasons.violation'), type: 'violation' }
]) ])
const [rules, setRules] = useState<{ selected: boolean; content: string; id: string }[]>([]) const [rules, setRules] = useState<{ selected: boolean; content: string; id: string }[]>([])
const [forward, setForward] = useState<boolean>(true) const [forward, setForward] = useState<boolean>(true)
@ -37,7 +37,7 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
const [isReporting, setIsReporting] = useState(false) const [isReporting, setIsReporting] = useState(false)
useEffect(() => { useEffect(() => {
navigation.setOptions({ navigation.setOptions({
title: t('shared.report.name', { acct: `@${account.acct}` }), title: t('screenTabs:shared.report.name', { acct: `@${account.acct}` }),
headerLeft: () => ( headerLeft: () => (
<HeaderLeft <HeaderLeft
type='text' type='text'
@ -48,7 +48,7 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
headerRight: () => ( headerRight: () => (
<HeaderRight <HeaderRight
type='text' type='text'
content={t('shared.report.report')} content={t('screenTabs:shared.report.report')}
destructive destructive
onPress={() => { onPress={() => {
const body = new FormData() const body = new FormData()
@ -119,7 +119,9 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
style={{ color: colors.primaryDefault, paddingRight: StyleConstants.Spacing.M }} style={{ color: colors.primaryDefault, paddingRight: StyleConstants.Spacing.M }}
numberOfLines={2} numberOfLines={2}
> >
{t('shared.report.forward.heading', { instance: account.acct.match(/@(.*)/)?.[1] })} {t('screenTabs:shared.report.forward.heading', {
instance: account.acct.match(/@(.*)/)?.[1]
})}
</CustomText> </CustomText>
<Switch <Switch
value={forward} value={forward}
@ -133,7 +135,7 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
fontStyle='M' fontStyle='M'
style={{ color: colors.primaryDefault, marginBottom: StyleConstants.Spacing.S }} style={{ color: colors.primaryDefault, marginBottom: StyleConstants.Spacing.S }}
> >
{t('shared.report.reasons.heading')} {t('screenTabs:shared.report.reasons.heading')}
</CustomText> </CustomText>
<View style={{ marginLeft: StyleConstants.Spacing.M }}> <View style={{ marginLeft: StyleConstants.Spacing.M }}>
<Selections options={categories} setOptions={setCategories} /> <Selections options={categories} setOptions={setCategories} />
@ -149,7 +151,7 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
marginBottom: StyleConstants.Spacing.XS marginBottom: StyleConstants.Spacing.XS
}} }}
> >
{t('shared.report.comment.heading')} {t('screenTabs:shared.report.comment.heading')}
</CustomText> </CustomText>
<View <View
style={{ style={{
@ -198,7 +200,7 @@ const TabSharedReport: React.FC<TabSharedStackScreenProps<'Tab-Shared-Report'>>
marginBottom: StyleConstants.Spacing.S marginBottom: StyleConstants.Spacing.S
}} }}
> >
{t('shared.report.violatedRules.heading')} {t('screenTabs:shared.report.violatedRules.heading')}
</CustomText> </CustomText>
<View style={{ marginLeft: StyleConstants.Spacing.M }}> <View style={{ marginLeft: StyleConstants.Spacing.M }}>
<Selections <Selections

View File

@ -38,7 +38,8 @@ const SearchEmpty: React.FC<Props> = ({ isFetching, inputRef, setSearchTerm }) =
}} }}
> >
<Trans <Trans
i18nKey='screenTabs:shared.search.empty.general' ns='screenTabs'
i18nKey='shared.search.empty.general'
components={{ components={{
bold: <CustomText fontWeight='Bold' /> bold: <CustomText fontWeight='Bold' />
}} }}

View File

@ -179,7 +179,8 @@ const TabSharedSearch: React.FC<TabSharedStackScreenProps<'Tab-Shared-Search'>>
> >
<CustomText fontStyle='S' style={{ textAlign: 'center', color: colors.secondary }}> <CustomText fontStyle='S' style={{ textAlign: 'center', color: colors.secondary }}>
<Trans <Trans
i18nKey='screenTabs:shared.search.notFound' ns='screenTabs'
i18nKey='shared.search.notFound'
values={{ searchTerm, type: translation }} values={{ searchTerm, type: translation }}
components={{ components={{
bold: <CustomText fontWeight='Bold' /> bold: <CustomText fontWeight='Bold' />

View File

@ -23,7 +23,9 @@ const TabSharedUsers: React.FC<TabSharedStackScreenProps<'Tab-Shared-Users'>> =
const { t } = useTranslation('screenTabs') const { t } = useTranslation('screenTabs')
useEffect(() => { useEffect(() => {
navigation.setOptions({ navigation.setOptions({
title: t(`shared.users.${params.reference}.${params.type}`, { count: params.count }), title: t(`shared.users.${params.reference}.${params.type}`, {
count: params.count
} as any) as any,
headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} /> headerLeft: () => <HeaderLeft onPress={() => navigation.goBack()} />
}) })
}, []) }, [])

View File

@ -1,5 +1,5 @@
import * as Sentry from "@sentry/react-native"; import * as Sentry from '@sentry/react-native'
import { isDevelopment } from "@utils/checkEnvironment"; import { isDevelopment } from '@utils/checkEnvironment'
import log from './log' import log from './log'
const sentry = () => { const sentry = () => {
@ -10,8 +10,8 @@ const sentry = () => {
tracesSampleRate: 0.35, tracesSampleRate: 0.35,
integrations: [ integrations: [
new Sentry.ReactNativeTracing({ new Sentry.ReactNativeTracing({
tracingOrigins: ["tooot.app"], tracingOrigins: ['api.tooot.app']
}), })
], ],
autoSessionTracking: true autoSessionTracking: true
}) })

View File

@ -129,7 +129,7 @@ const useProfileMutation = () => {
displayMessage({ displayMessage({
ref: variables.messageRef, ref: variables.messageRef,
message: i18next.t('screenTabs:me.profile.feedback.failed', { message: i18next.t('screenTabs:me.profile.feedback.failed', {
type: i18next.t(`screenTabs:${variables.message.text}`) type: i18next.t(`screenTabs:${variables.message.text}` as any)
}), }),
...(err && { description: err.message }), ...(err && { description: err.message }),
type: 'danger' type: 'danger'
@ -142,7 +142,7 @@ const useProfileMutation = () => {
displayMessage({ displayMessage({
ref: variables.messageRef, ref: variables.messageRef,
message: i18next.t('screenTabs:me.profile.feedback.succeed', { message: i18next.t('screenTabs:me.profile.feedback.succeed', {
type: i18next.t(`screenTabs:${variables.message.text}`) type: i18next.t(`screenTabs:${variables.message.text}` as any)
}), }),
type: 'success' type: 'success'
}) })

View File

@ -70,7 +70,7 @@ export const setChannels = async (instance: InstanceLatest, reset: boolean | und
const setChannel = async (type: string) => const setChannel = async (type: string) =>
Notifications.setNotificationChannelAsync(`${account}_${type}`, { Notifications.setNotificationChannelAsync(`${account}_${type}`, {
groupId: account, groupId: account,
name: i18n.t(`screenTabs:me.push.${type}.heading`), name: i18n.t(`screenTabs:me.push.${type}.heading` as any),
importance: Notifications.AndroidImportance.DEFAULT, importance: Notifications.AndroidImportance.DEFAULT,
bypassDnd: false, bypassDnd: false,
showBadge: true, showBadge: true,

952
yarn.lock

File diff suppressed because it is too large Load Diff