Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(locales): add intellisense for translations #5974

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .tsbuildinfo

Large diffs are not rendered by default.

13 changes: 11 additions & 2 deletions locales/base/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@
"cancel": "Cancel",
"changeProfilePhoto": "Change Profile Photo",
"name": "Name",
"Name": "Name",
"Email": "Email",
"editName": "Edit Name",
"submit": "Submit",
"selectLanguage": "Select Language",
Expand Down Expand Up @@ -831,6 +833,7 @@
"biometryType": {
"FaceID": "Face ID",
"TouchID": "Touch ID",
"OpticID": "Optic ID",
"Fingerprint": "Fingerprint recognition",
"Face": "Face recognition",
"Iris": "Iris recognition"
Expand Down Expand Up @@ -1168,10 +1171,12 @@
"signTransaction": "{{dappName}} would like to sign a transaction.",
"signDappTransaction": "{{dappName}} would like to sign a transaction on the {{networkName}} network.",
"signDappTransactionUnsupportedNetwork": "{{dappName}} would like to sign a transaction on an unsupported network.",
"signDappTransactionUnknownNetwork": "{{dappName}} would like to sign a transaction on an unsupported network.",
"sendTransactionTitle": "Send transaction",
"sendTransaction": "{{dappName}} would like to send a transaction.",
"sendDappTransaction": "{{dappName}} would like to send a transaction on the {{networkName}} network.",
"sendDappTransactionUnsupportedNetwork": "{{dappName}} would like to send a transaction on an unsupported network.",
"sendDappTransactionUnknownNetwork": "{{dappName}} would like to send a transaction on an unsupported network.",
"decryptPayloadTitle": "Decrypt with wallet",
"decryptPayload": "{{dappName}} would like to decrypt a data payload.",
"computeSharedSecret": "{{dappName}} would like to generate secrets.",
Expand Down Expand Up @@ -1741,7 +1746,8 @@
"label": "Account Number",
"placeholderText": "Enter Account Number",
"errorMessageDigitLength": "Account number must be {{length}} digits",
"errorMessageDigit": "Account number must contain only digits"
"errorMessageDigit": "Account number must contain only digits",
"notExactMatch": "Account number doesn't match \"{{expected}}\""
},
"mobileMoney": {
"operator": {
Expand Down Expand Up @@ -2746,5 +2752,8 @@
"duration_year_one": "1 year",
"duration_year_other": "{{count}} years",
"duration_yearMonth_one": "1 year, 1 month",
"duration_yearMonth_other": "{{count}} years, {{count2}} months"
"duration_yearMonth_other": "{{count}} years, {{count2}} months",
"transactionTimeout": "Transaction Timeout",
"keychainFetchAccounts": "Keychain Fetch Accounts",
"keychainAccountAlreadyExists": "Keychain Fetch Accounts Already Exists"
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
"deploy:update-disclaimer": "yarn licenses generate-disclaimer --prod > src/account/LicenseDisclaimer.txt && ./scripts/copy_license_to_android_assets.sh",
"postinstall": "patch-package && yarn keys:decrypt && ./scripts/copy_license_to_android_assets.sh",
"keys:decrypt": "bash scripts/key_placer.sh decrypt",
"keys:encrypt": "bash scripts/key_placer.sh encrypt"
"keys:encrypt": "bash scripts/key_placer.sh encrypt",
"i18n:generate-interface": "i18next-resources-for-ts interface -i ./locales/base -o ./src/i18n/i18next-resources.d.ts"
},
"husky": {
"hooks": {
Expand Down Expand Up @@ -247,6 +248,7 @@
"ethers": "^5.7.2",
"expect": "^29.7.0",
"husky": "^3.0.0",
"i18next-resources-for-ts": "^1.5.0",
"jest": "^29.6.2",
"jest-circus": "^29.6.2",
"jest-diff": "^29.6.4",
Expand Down
49 changes: 31 additions & 18 deletions src/account/AccountKeyEducation.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { NativeStackScreenProps } from '@react-navigation/native-stack'
import React, { useEffect } from 'react'
import React, { useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native'
import Education, { EducationTopic } from 'src/account/Education'
import { OnboardingEvents } from 'src/analytics/Events'
import Education, { type EducationStep, EducationTopic } from 'src/account/Education'
import AppAnalytics from 'src/analytics/AppAnalytics'
import { OnboardingEvents } from 'src/analytics/Events'
import { BtnTypes } from 'src/components/Button'
import { accountKey1, accountKey2, accountKey3, accountKey4 } from 'src/images/Images'
import { noHeader } from 'src/navigator/Headers'
Expand Down Expand Up @@ -52,22 +52,35 @@ AccountKeyEducation.navigationOptions = {
}),
}

function useSteps() {
function useSteps(): EducationStep[] {
const { t } = useTranslation()
return React.useMemo(
() =>
[
{ image: accountKey1, topic: EducationTopic.backup },
{ image: accountKey2, topic: EducationTopic.backup },
{ image: accountKey3, topic: EducationTopic.backup },
{ image: accountKey4, topic: EducationTopic.backup },
].map((step, index) => {
return {
...step,
title: t(`guide.${index}.title`),
text: t(`guide.${index}.text`),
}
}),
return useMemo(
() => [
{
image: accountKey1,
topic: EducationTopic.backup,
title: t(`guide.0.title`),
text: t(`guide.0.text`),
},
{
image: accountKey2,
topic: EducationTopic.backup,
title: t(`guide.1.title`),
text: t(`guide.1.text`),
},
{
image: accountKey3,
topic: EducationTopic.backup,
title: t(`guide.2.title`),
text: t(`guide.2.text`),
},
{
image: accountKey4,
topic: EducationTopic.backup,
title: t(`guide.3.title`),
text: t(`guide.3.text`),
},
],
[]
)
}
2 changes: 1 addition & 1 deletion src/account/Education.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export enum EducationTopic {
celo = 'celo',
}

interface EducationStep {
export interface EducationStep {
image: ImageSourcePropType | null
topic: EducationTopic
title: string
Expand Down
26 changes: 14 additions & 12 deletions src/account/GoldEducation.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { useEffect } from 'react'
import React, { useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { Platform } from 'react-native'
import Education, { EducationTopic } from 'src/account/Education'
import Education, { type EducationStep, EducationTopic } from 'src/account/Education'
import { setGoldEducationCompleted } from 'src/account/actions'
import { celoEducationCompletedSelector } from 'src/account/selectors'
import { OnboardingEvents } from 'src/analytics/Events'
import AppAnalytics from 'src/analytics/AppAnalytics'
import { OnboardingEvents } from 'src/analytics/Events'
import { BtnTypes } from 'src/components/Button'
import { celoEducation1, celoEducation2, celoEducation3, celoEducation4 } from 'src/images/Images'
import { noHeader } from 'src/navigator/Headers'
Expand Down Expand Up @@ -54,33 +54,35 @@ GoldEducation.navigationOptions = {
}),
}

function useStep() {
function useStep(): EducationStep[] {
const { t } = useTranslation()

return React.useMemo(() => {
return useMemo(() => {
return [
{
image: celoEducation1,
topic: EducationTopic.celo,
title: t(`goldEducationSteps.0.title`),
text: t(`goldEducationSteps.0.text`),
},
{
image: celoEducation2,
topic: EducationTopic.celo,
title: t(`goldEducationSteps.1.title`),
text: t(`goldEducationSteps.1.text`),
},
{
image: celoEducation3,
topic: EducationTopic.celo,
title: t(`goldEducationSteps.2.title`),
text: t(`goldEducationSteps.2.text`),
},
{
image: celoEducation4, // Placeholder Image
topic: EducationTopic.celo,
title: t(`goldEducationSteps.3.title`),
text: t(`goldEducationSteps.3.text`),
},
].map((step, index) => {
return {
...step,
title: t(`goldEducationSteps.${index}.title`),
text: t(`goldEducationSteps.${index}.text`),
}
})
]
}, [])
}
10 changes: 6 additions & 4 deletions src/alert/actions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TOptions } from 'i18next'
import { ErrorDisplayType } from 'src/alert/reducer'
import { AppEvents } from 'src/analytics/Events'
import AppAnalytics from 'src/analytics/AppAnalytics'
import { AppEvents } from 'src/analytics/Events'
import { OpenUrlAction } from 'src/app/actions'
import { ErrorMessages } from 'src/app/ErrorMessages'
import { ALERT_BANNER_DURATION } from 'src/config'
Expand Down Expand Up @@ -58,12 +58,13 @@ export const showToast = (
export const showError = (
error: ErrorMessages,
dismissAfter?: number | null | undefined,
i18nOptions?: object
i18nOptions?: TOptions
): ShowAlertAction => {
AppAnalytics.track(AppEvents.error_displayed, { error })
return showAlert(
AlertTypes.ERROR,
i18n.t(error, { ...(i18nOptions || {}) }),
// @ts-expect-error
i18n.t(error, i18nOptions ?? {}),
dismissAfter,
null,
null,
Expand All @@ -76,7 +77,8 @@ export const showErrorInline = (error: ErrorMessages, i18nOptions?: TOptions): S
type: Actions.SHOW,
alertType: AlertTypes.ERROR,
displayMethod: ErrorDisplayType.INLINE,
message: i18n.t(error, { ...(i18nOptions || {}) }),
// @ts-expect-error
message: i18n.t(error, i18nOptions || {}),
underlyingError: error,
})

Expand Down
2 changes: 2 additions & 0 deletions src/app/ErrorMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ export enum ErrorMessages {
SHORTCUT_CLAIM_REWARD_FAILED = 'dappShortcuts.claimRewardFailure',
INVITE_WITH_URL_FAILED = 'inviteWithUrl.error',
}

export type ErrorMessagesTranslationKeys = `${ErrorMessages}`
2 changes: 1 addition & 1 deletion src/app/ErrorScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class ErrorScreen extends React.Component<Props> {
>
<View>
<Text style={styles.errorMessage} numberOfLines={10} ellipsizeMode="tail">
{t(errorMessage)}
{t(errorMessage as unknown as any)}
</Text>
</View>
</FullscreenCTA>
Expand Down
9 changes: 6 additions & 3 deletions src/backup/BackupQuiz.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { SafeAreaView } from 'react-native-safe-area-context'
import { connect } from 'react-redux'
import { setBackupCompleted } from 'src/account/actions'
import { showError } from 'src/alert/actions'
import AppAnalytics from 'src/analytics/AppAnalytics'
import { OnboardingEvents } from 'src/analytics/Events'
import { BackQuizProgress } from 'src/analytics/types'
import AppAnalytics from 'src/analytics/AppAnalytics'
import CancelConfirm from 'src/backup/CancelConfirm'
import { QuizzBottom } from 'src/backup/QuizzBottom'
import { getStoredMnemonic, onGetMnemonicFail } from 'src/backup/utils'
Expand All @@ -27,6 +27,7 @@ import { RootState } from 'src/redux/reducers'
import colors from 'src/styles/colors'
import { typeScale } from 'src/styles/fonts'
import Logger from 'src/utils/Logger'
import type { NumberRange } from 'src/utils/typescript'
import { currentAccountSelector } from 'src/web3/selectors'

const TAG = 'backup/BackupQuiz'
Expand Down Expand Up @@ -211,7 +212,7 @@ export class BackupQuiz extends React.Component<Props, State> {
render() {
const { t } = this.props
const { mnemonicWords: mnemonicWordButtons, userChosenWords, mnemonicLength } = this.state
const currentWordIndex = userChosenWords.length + 1
const currentWordIndex = (userChosenWords.length + 1) as NumberRange<0, 30>
const isQuizComplete = userChosenWords.length === mnemonicLength && mnemonicLength !== 0
const mnemonicWordsToDisplay = mnemonicWordButtons.slice(0, MNEMONIC_BUTTONS_TO_DISPLAY)
return (
Expand Down Expand Up @@ -247,7 +248,9 @@ export class BackupQuiz extends React.Component<Props, State> {
<Text style={styles.bodyText}>
<Trans
i18nKey={'backupQuizWordCountV1_83'}
tOptions={{ wordNumber: t(`ordinals.${currentWordIndex}`) }}
tOptions={{
wordNumber: t(`ordinals.${currentWordIndex}`),
}}
>
<Text style={styles.bodyTextBold}>X</Text>
</Trans>
Expand Down
4 changes: 2 additions & 2 deletions src/components/ErrorMessageInline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { StyleSheet, Text, View } from 'react-native'
import { connect } from 'react-redux'
import { hideAlert } from 'src/alert/actions'
import { ErrorDisplayType } from 'src/alert/reducer'
import { ErrorMessages } from 'src/app/ErrorMessages'
import { ErrorMessages, type ErrorMessagesTranslationKeys } from 'src/app/ErrorMessages'
import { withTranslation } from 'src/i18n'
import { RootState } from 'src/redux/reducers'
import colors from 'src/styles/colors'
Expand Down Expand Up @@ -57,7 +57,7 @@ function ErrorMessageInline(props: Props) {

return (
<View style={dismissAfter !== null && styles.errorContainer}>
<Text style={styles.errorMessage}>{t(error)} </Text>
<Text style={styles.errorMessage}>{t(error as ErrorMessagesTranslationKeys)} </Text>
</View>
)
}
Expand Down
15 changes: 14 additions & 1 deletion src/components/InviteOptionsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'
import { Share } from 'react-native'
import AppAnalytics from 'src/analytics/AppAnalytics'
import { InviteEvents } from 'src/analytics/Events'
import i18n from 'src/i18n'
import InviteModal from 'src/invite/InviteModal'
import { useShareUrl } from 'src/invite/hooks'
import { Recipient, getDisplayName } from 'src/recipients/recipient'
Expand Down Expand Up @@ -40,24 +41,36 @@ const InviteOptionsModal = ({ recipient, onClose }: Props) => {
onClose()
}

let title = t('inviteModal.title', { contactName: getDisplayName(recipient, t) })
/**
* As of now, TS type of i18next doesn't include "defaultVariables" (e.g. "appName") into the
* interpolated type so every translation that will use any values from "defaultVariables" will
* be required to provide them explicitly.
*/

//@ts-expect-error
let title = i18n.t('inviteModal.title', { contactName: getDisplayName(recipient, t) })
let descriptionI18nKey = 'inviteModal.body'
//@ts-expect-error
let message = t('inviteModal.shareMessage', { link })
let helpLink = ''

if (inviteRewardsActive) {
switch (inviteRewardsType) {
case InviteRewardsType.NFT:
//@ts-expect-error
title = t('inviteModal.rewardsActive.title', { contactName: getDisplayName(recipient, t) })
descriptionI18nKey = 'inviteModal.rewardsActive.body'
//@ts-expect-error
message = t('inviteWithRewards', { link })
helpLink = links.inviteRewardsNftsLearnMore
break
case InviteRewardsType.CUSD:
//@ts-expect-error
title = t('inviteModal.rewardsActiveCUSD.title', {
contactName: getDisplayName(recipient, t),
})
descriptionI18nKey = 'inviteModal.rewardsActiveCUSD.body'
//@ts-expect-error
message = t('inviteWithRewardsCUSD', { link })
helpLink = links.inviteRewardsStableTokenLearnMore
break
Expand Down
1 change: 1 addition & 0 deletions src/earn/EarnEnterAmount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ function FeeDetailsBottomSheet({
</Text>
{swapFeeAmount ? (
<Text style={styles.bottomSheetDescriptionText}>
{/* @ts-expect-error */}
{t('earnFlow.enterAmount.feeBottomSheet.networkSwapFeeDescription', {
appFeePercentage: swapTransaction?.appFeePercentageIncludedInPrice,
})}
Expand Down
Loading
Loading