mirror of
https://github.com/tooot-app/app
synced 2025-05-23 06:54:16 +02:00
parent
bdf7da120f
commit
af6731f702
10
README.md
10
README.md
@ -6,10 +6,12 @@
|
||||
|
||||
## Special thanks
|
||||
|
||||
@forenta for German translation
|
||||
[@forenta](https://github.com/forenta) for German translation
|
||||
|
||||
@andrigamerita for Italian translation
|
||||
[@andrigamerita](https://github.com/andrigamerita) for Italian translation
|
||||
|
||||
@hellojaccc for Korean translation
|
||||
[@hellojaccc](https://github.com/hellojaccc) for Korean translation
|
||||
|
||||
@duy@mas.to for Vietnamese translation
|
||||
[@luizpicolo](https://github.com/luizpicolo) for Brazilian Portuguese
|
||||
|
||||
[@duy@mas.to](https://mas.to/@duy) for Vietnamese translation
|
||||
|
@ -4,7 +4,7 @@
|
||||
"native": "220508",
|
||||
"major": 4,
|
||||
"minor": 0,
|
||||
"patch": 3,
|
||||
"patch": 4,
|
||||
"expo": "45.0.0"
|
||||
},
|
||||
"description": "tooot app for Mastodon",
|
||||
|
27
src/App.tsx
27
src/App.tsx
@ -1,31 +1,4 @@
|
||||
import { ActionSheetProvider } from '@expo/react-native-action-sheet'
|
||||
import '@formatjs/intl-getcanonicallocales/polyfill'
|
||||
import '@formatjs/intl-locale/polyfill'
|
||||
import '@formatjs/intl-pluralrules/polyfill'
|
||||
import '@formatjs/intl-pluralrules/locale-data/de'
|
||||
import '@formatjs/intl-pluralrules/locale-data/en'
|
||||
import '@formatjs/intl-pluralrules/locale-data/ko'
|
||||
import '@formatjs/intl-pluralrules/locale-data/vi'
|
||||
import '@formatjs/intl-pluralrules/locale-data/zh'
|
||||
import '@formatjs/intl-numberformat/polyfill'
|
||||
import '@formatjs/intl-numberformat/locale-data/de'
|
||||
import '@formatjs/intl-numberformat/locale-data/en'
|
||||
import '@formatjs/intl-numberformat/locale-data/ko'
|
||||
import '@formatjs/intl-numberformat/locale-data/vi'
|
||||
import '@formatjs/intl-numberformat/locale-data/zh'
|
||||
import '@formatjs/intl-datetimeformat/polyfill'
|
||||
import '@formatjs/intl-datetimeformat/locale-data/de'
|
||||
import '@formatjs/intl-datetimeformat/locale-data/en'
|
||||
import '@formatjs/intl-datetimeformat/locale-data/ko'
|
||||
import '@formatjs/intl-datetimeformat/locale-data/vi'
|
||||
import '@formatjs/intl-datetimeformat/locale-data/zh'
|
||||
import '@formatjs/intl-datetimeformat/add-all-tz'
|
||||
import '@formatjs/intl-relativetimeformat/polyfill'
|
||||
import '@formatjs/intl-relativetimeformat/locale-data/de'
|
||||
import '@formatjs/intl-relativetimeformat/locale-data/en'
|
||||
import '@formatjs/intl-relativetimeformat/locale-data/ko'
|
||||
import '@formatjs/intl-relativetimeformat/locale-data/vi'
|
||||
import '@formatjs/intl-relativetimeformat/locale-data/zh'
|
||||
import queryClient from '@helpers/queryClient'
|
||||
import i18n from '@root/i18n/i18n'
|
||||
import Screens from '@root/Screens'
|
||||
|
@ -22,7 +22,7 @@ export interface Props {
|
||||
switchDisabled?: boolean
|
||||
switchOnValueChange?: () => void
|
||||
|
||||
iconBack?: 'ChevronRight' | 'ExternalLink'
|
||||
iconBack?: 'ChevronRight' | 'ExternalLink' | 'Check'
|
||||
iconBackColor?: ColorDefinitions
|
||||
|
||||
loading?: boolean
|
||||
|
@ -43,6 +43,9 @@
|
||||
"fontSize": {
|
||||
"name": "Toot Font Size"
|
||||
},
|
||||
"language": {
|
||||
"name": "Language"
|
||||
},
|
||||
"lists": {
|
||||
"name": "Lists"
|
||||
},
|
||||
@ -221,7 +224,7 @@
|
||||
}
|
||||
},
|
||||
"language": {
|
||||
"heading": "Language",
|
||||
"heading": "$t(me.stacks.language.name)",
|
||||
"options": {
|
||||
"cancel": "$t(common:buttons.cancel)"
|
||||
}
|
||||
|
@ -5,9 +5,42 @@ import de from '@root/i18n/de/_all'
|
||||
import en from '@root/i18n/en/_all'
|
||||
import it from '@root/i18n/it/_all'
|
||||
import ko from '@root/i18n/ko/_all'
|
||||
import pt_BR from '@root/i18n/pt_BR/_all'
|
||||
import vi from '@root/i18n/vi/_all'
|
||||
import zh_Hans from '@root/i18n/zh-Hans/_all'
|
||||
|
||||
import '@formatjs/intl-getcanonicallocales/polyfill'
|
||||
import '@formatjs/intl-locale/polyfill'
|
||||
import '@formatjs/intl-pluralrules/polyfill'
|
||||
import '@formatjs/intl-pluralrules/locale-data/de'
|
||||
import '@formatjs/intl-pluralrules/locale-data/en'
|
||||
import '@formatjs/intl-pluralrules/locale-data/ko'
|
||||
import '@formatjs/intl-pluralrules/locale-data/pt'
|
||||
import '@formatjs/intl-pluralrules/locale-data/vi'
|
||||
import '@formatjs/intl-pluralrules/locale-data/zh'
|
||||
import '@formatjs/intl-numberformat/polyfill'
|
||||
import '@formatjs/intl-numberformat/locale-data/de'
|
||||
import '@formatjs/intl-numberformat/locale-data/en'
|
||||
import '@formatjs/intl-numberformat/locale-data/ko'
|
||||
import '@formatjs/intl-numberformat/locale-data/pt'
|
||||
import '@formatjs/intl-numberformat/locale-data/vi'
|
||||
import '@formatjs/intl-numberformat/locale-data/zh-Hans'
|
||||
import '@formatjs/intl-datetimeformat/polyfill'
|
||||
import '@formatjs/intl-datetimeformat/locale-data/de'
|
||||
import '@formatjs/intl-datetimeformat/locale-data/en'
|
||||
import '@formatjs/intl-datetimeformat/locale-data/ko'
|
||||
import '@formatjs/intl-datetimeformat/locale-data/pt'
|
||||
import '@formatjs/intl-datetimeformat/locale-data/vi'
|
||||
import '@formatjs/intl-datetimeformat/locale-data/zh-Hans'
|
||||
import '@formatjs/intl-datetimeformat/add-all-tz'
|
||||
import '@formatjs/intl-relativetimeformat/polyfill'
|
||||
import '@formatjs/intl-relativetimeformat/locale-data/de'
|
||||
import '@formatjs/intl-relativetimeformat/locale-data/en'
|
||||
import '@formatjs/intl-relativetimeformat/locale-data/ko'
|
||||
import '@formatjs/intl-relativetimeformat/locale-data/pt'
|
||||
import '@formatjs/intl-relativetimeformat/locale-data/vi'
|
||||
import '@formatjs/intl-relativetimeformat/locale-data/zh-Hans'
|
||||
|
||||
i18n.use(initReactI18next).init({
|
||||
lng: 'en',
|
||||
fallbackLng: 'en',
|
||||
@ -15,7 +48,7 @@ i18n.use(initReactI18next).init({
|
||||
ns: ['common'],
|
||||
defaultNS: 'common',
|
||||
|
||||
resources: { 'zh-Hans': zh_Hans, vi, ko, it, en, de },
|
||||
resources: { 'zh-Hans': zh_Hans, vi, 'pt-BR': pt_BR, ko, it, en, de },
|
||||
returnEmptyString: false,
|
||||
|
||||
saveMissing: true,
|
||||
|
@ -3,6 +3,7 @@ const LOCALES = {
|
||||
en: 'English',
|
||||
it: 'Italiano',
|
||||
ko: '한국어',
|
||||
'pt-BR': 'Português (Brasil)',
|
||||
vi: 'Tiếng Việt',
|
||||
'zh-Hans': '简体中文'
|
||||
}
|
||||
|
17
src/i18n/pt_BR/_all.ts
Normal file
17
src/i18n/pt_BR/_all.ts
Normal file
@ -0,0 +1,17 @@
|
||||
export default {
|
||||
common: require('./common'),
|
||||
|
||||
screens: require('./screens'),
|
||||
screenActions: require('./screens/actions'),
|
||||
screenAnnouncements: require('./screens/announcements'),
|
||||
screenCompose: require('./screens/compose'),
|
||||
screenImageViewer: require('./screens/imageViewer'),
|
||||
screenTabs: require('./screens/tabs'),
|
||||
|
||||
componentEmojis: require('./components/emojis'),
|
||||
componentInstance: require('./components/instance'),
|
||||
componentMediaSelector: require('./components/mediaSelector'),
|
||||
componentParse: require('./components/parse'),
|
||||
componentRelationship: require('./components/relationship'),
|
||||
componentTimeline: require('./components/timeline')
|
||||
}
|
@ -14,6 +14,7 @@ import TabMePush from './Me/Push'
|
||||
import TabMeRoot from './Me/Root'
|
||||
import TabMeSettings from './Me/Settings'
|
||||
import TabMeSettingsFontsize from './Me/SettingsFontsize'
|
||||
import TabMeSettingsLanguage from './Me/SettingsLanguage'
|
||||
import TabMeSwitch from './Me/Switch'
|
||||
import TabSharedRoot from './Shared/Root'
|
||||
|
||||
@ -152,6 +153,19 @@ const TabMe = React.memo(
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Tab-Me-Settings-Language'
|
||||
component={TabMeSettingsLanguage}
|
||||
options={({ navigation }: any) => ({
|
||||
title: t('me.stacks.language.name'),
|
||||
...(Platform.OS === 'android' && {
|
||||
headerCenter: () => (
|
||||
<HeaderCenter content={t('me.stacks.language.name')} />
|
||||
)
|
||||
}),
|
||||
headerLeft: () => <HeaderLeft onPress={() => navigation.pop(1)} />
|
||||
})}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name='Tab-Me-Switch'
|
||||
component={TabMeSwitch}
|
||||
|
@ -5,11 +5,8 @@ import { useActionSheet } from '@expo/react-native-action-sheet'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { LOCALES } from '@root/i18n/locales'
|
||||
import { useAppDispatch } from '@root/store'
|
||||
import androidDefaults from '@utils/slices/instances/push/androidDefaults'
|
||||
import { getInstances } from '@utils/slices/instancesSlice'
|
||||
import {
|
||||
changeBrowser,
|
||||
changeLanguage,
|
||||
changeTheme,
|
||||
getSettingsTheme,
|
||||
getSettingsBrowser,
|
||||
@ -19,11 +16,8 @@ import {
|
||||
getSettingsStaticEmoji,
|
||||
changeStaticEmoji
|
||||
} from '@utils/slices/settingsSlice'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Platform } from 'react-native'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { mapFontsizeToName } from '../SettingsFontsize'
|
||||
|
||||
@ -31,10 +25,8 @@ const SettingsApp: React.FC = () => {
|
||||
const navigation = useNavigation<any>()
|
||||
const dispatch = useAppDispatch()
|
||||
const { showActionSheetWithOptions } = useActionSheet()
|
||||
const { mode } = useTheme()
|
||||
const { t, i18n } = useTranslation('screenTabs')
|
||||
|
||||
const instances = useSelector(getInstances, () => true)
|
||||
const settingsFontsize = useSelector(getSettingsFontsize)
|
||||
const settingsTheme = useSelector(getSettingsTheme)
|
||||
const settingsDarkTheme = useSelector(getSettingsDarkTheme)
|
||||
@ -49,102 +41,14 @@ const SettingsApp: React.FC = () => {
|
||||
`me.settings.fontsize.content.${mapFontsizeToName(settingsFontsize)}`
|
||||
)}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() => {
|
||||
navigation.navigate('Tab-Me-Settings-Fontsize')
|
||||
}}
|
||||
onPress={() => navigation.navigate('Tab-Me-Settings-Fontsize')}
|
||||
/>
|
||||
<MenuRow
|
||||
title={t('me.settings.language.heading')}
|
||||
// @ts-ignore
|
||||
content={LOCALES[i18n.language]}
|
||||
iconBack='ChevronRight'
|
||||
onPress={() => {
|
||||
const options = Object.keys(LOCALES)
|
||||
// @ts-ignore
|
||||
.map(locale => LOCALES[locale])
|
||||
.concat(t('me.settings.language.options.cancel'))
|
||||
|
||||
showActionSheetWithOptions(
|
||||
{
|
||||
title: t('me.settings.language.heading'),
|
||||
options,
|
||||
cancelButtonIndex: options.length - 1,
|
||||
userInterfaceStyle: mode
|
||||
},
|
||||
buttonIndex => {
|
||||
if (buttonIndex === undefined) return
|
||||
if (buttonIndex < options.length - 1) {
|
||||
analytics('settings_language_press', {
|
||||
current: i18n.language,
|
||||
new: options[buttonIndex]
|
||||
})
|
||||
haptics('Success')
|
||||
|
||||
// @ts-ignore
|
||||
dispatch(changeLanguage(Object.keys(LOCALES)[buttonIndex]))
|
||||
i18n.changeLanguage(Object.keys(LOCALES)[buttonIndex])
|
||||
|
||||
// Update Android notification channel language
|
||||
if (Platform.OS === 'android') {
|
||||
instances.forEach(instance => {
|
||||
const accountFull = `@${instance.account.acct}@${instance.uri}`
|
||||
if (instance.push.decode.value === false) {
|
||||
Notifications.setNotificationChannelAsync(
|
||||
`${accountFull}_default`,
|
||||
{
|
||||
groupId: accountFull,
|
||||
name: t('me.push.default.heading'),
|
||||
...androidDefaults
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Notifications.setNotificationChannelAsync(
|
||||
`${accountFull}_follow`,
|
||||
{
|
||||
groupId: accountFull,
|
||||
name: t('me.push.follow.heading'),
|
||||
...androidDefaults
|
||||
}
|
||||
)
|
||||
Notifications.setNotificationChannelAsync(
|
||||
`${accountFull}_favourite`,
|
||||
{
|
||||
groupId: accountFull,
|
||||
name: t('me.push.favourite.heading'),
|
||||
...androidDefaults
|
||||
}
|
||||
)
|
||||
Notifications.setNotificationChannelAsync(
|
||||
`${accountFull}_reblog`,
|
||||
{
|
||||
groupId: accountFull,
|
||||
name: t('me.push.reblog.heading'),
|
||||
...androidDefaults
|
||||
}
|
||||
)
|
||||
Notifications.setNotificationChannelAsync(
|
||||
`${accountFull}_mention`,
|
||||
{
|
||||
groupId: accountFull,
|
||||
name: t('me.push.mention.heading'),
|
||||
...androidDefaults
|
||||
}
|
||||
)
|
||||
Notifications.setNotificationChannelAsync(
|
||||
`${accountFull}_poll`,
|
||||
{
|
||||
groupId: accountFull,
|
||||
name: t('me.push.poll.heading'),
|
||||
...androidDefaults
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}}
|
||||
onPress={() => navigation.navigate('Tab-Me-Settings-Language')}
|
||||
/>
|
||||
<MenuRow
|
||||
title={t('me.settings.theme.heading')}
|
||||
|
@ -45,7 +45,7 @@ const TabMeSettingsFontsize: React.FC<
|
||||
const item = {
|
||||
id: 'demo',
|
||||
uri: 'https://tooot.app',
|
||||
created_at: new Date(),
|
||||
created_at: new Date(2021, 4, 16),
|
||||
sensitive: false,
|
||||
visibility: 'public',
|
||||
replies_count: 0,
|
||||
@ -67,6 +67,7 @@ const TabMeSettingsFontsize: React.FC<
|
||||
username: 'tooot📱',
|
||||
acct: 'tooot@xmflsct.com',
|
||||
display_name: 'tooot📱',
|
||||
avatar: 'https://avatars.githubusercontent.com/u/77554750?s=100',
|
||||
avatar_static: 'https://avatars.githubusercontent.com/u/77554750?s=100'
|
||||
},
|
||||
media_attachments: [],
|
||||
@ -100,7 +101,7 @@ const TabMeSettingsFontsize: React.FC<
|
||||
}, [theme, initialSize])
|
||||
|
||||
return (
|
||||
<ScrollView scrollEnabled={false}>
|
||||
<ScrollView>
|
||||
<CustomText
|
||||
fontStyle='M'
|
||||
style={{
|
||||
|
97
src/screens/Tabs/Me/SettingsLanguage.tsx
Normal file
97
src/screens/Tabs/Me/SettingsLanguage.tsx
Normal file
@ -0,0 +1,97 @@
|
||||
import analytics from '@components/analytics'
|
||||
import haptics from '@components/haptics'
|
||||
import { MenuContainer, MenuRow } from '@components/Menu'
|
||||
import { LOCALES } from '@root/i18n/locales'
|
||||
import { TabMeStackScreenProps } from '@utils/navigation/navigators'
|
||||
import androidDefaults from '@utils/slices/instances/push/androidDefaults'
|
||||
import { getInstances } from '@utils/slices/instancesSlice'
|
||||
import { changeLanguage } from '@utils/slices/settingsSlice'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FlatList, Platform } from 'react-native'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
|
||||
const TabMeSettingsLanguage: React.FC<
|
||||
TabMeStackScreenProps<'Tab-Me-Settings-Language'>
|
||||
> = () => {
|
||||
const { i18n, t } = useTranslation('screenTabs')
|
||||
const languages = Object.entries(LOCALES)
|
||||
const instances = useSelector(getInstances)
|
||||
const dispatch = useDispatch()
|
||||
|
||||
const change = (lang: string) => {
|
||||
analytics('settings_language_press', {
|
||||
current: i18n.language,
|
||||
new: lang
|
||||
})
|
||||
haptics('Success')
|
||||
|
||||
dispatch(changeLanguage(lang))
|
||||
i18n.changeLanguage(lang)
|
||||
|
||||
// Update Android notification channel language
|
||||
if (Platform.OS === 'android') {
|
||||
instances.forEach(instance => {
|
||||
const accountFull = `@${instance.account.acct}@${instance.uri}`
|
||||
if (instance.push.decode.value === false) {
|
||||
Notifications.setNotificationChannelAsync(`${accountFull}_default`, {
|
||||
groupId: accountFull,
|
||||
name: t('me.push.default.heading'),
|
||||
...androidDefaults
|
||||
})
|
||||
} else {
|
||||
Notifications.setNotificationChannelAsync(`${accountFull}_follow`, {
|
||||
groupId: accountFull,
|
||||
name: t('me.push.follow.heading'),
|
||||
...androidDefaults
|
||||
})
|
||||
Notifications.setNotificationChannelAsync(
|
||||
`${accountFull}_favourite`,
|
||||
{
|
||||
groupId: accountFull,
|
||||
name: t('me.push.favourite.heading'),
|
||||
...androidDefaults
|
||||
}
|
||||
)
|
||||
Notifications.setNotificationChannelAsync(`${accountFull}_reblog`, {
|
||||
groupId: accountFull,
|
||||
name: t('me.push.reblog.heading'),
|
||||
...androidDefaults
|
||||
})
|
||||
Notifications.setNotificationChannelAsync(`${accountFull}_mention`, {
|
||||
groupId: accountFull,
|
||||
name: t('me.push.mention.heading'),
|
||||
...androidDefaults
|
||||
})
|
||||
Notifications.setNotificationChannelAsync(`${accountFull}_poll`, {
|
||||
groupId: accountFull,
|
||||
name: t('me.push.poll.heading'),
|
||||
...androidDefaults
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<MenuContainer>
|
||||
<FlatList
|
||||
data={languages}
|
||||
renderItem={({ item }) => {
|
||||
return (
|
||||
<MenuRow
|
||||
key={item[0]}
|
||||
title={item[1]}
|
||||
iconBack={item[0] === i18n.language ? 'Check' : undefined}
|
||||
iconBackColor={'blue'}
|
||||
onPress={() => item[0] !== i18n.language && change(item[0])}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</MenuContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default TabMeSettingsLanguage
|
@ -146,6 +146,7 @@ export type TabMeStackParamList = {
|
||||
'Tab-Me-Push': undefined
|
||||
'Tab-Me-Settings': undefined
|
||||
'Tab-Me-Settings-Fontsize': undefined
|
||||
'Tab-Me-Settings-Language': undefined
|
||||
'Tab-Me-Switch': undefined
|
||||
} & TabSharedStackParamList
|
||||
export type TabMeStackScreenProps<T extends keyof TabMeStackParamList> =
|
||||
|
Loading…
x
Reference in New Issue
Block a user