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

[SLT-145] feat(synapse-interface): Adds internationalization #3096

Merged
merged 35 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
e2c0684
Adds next-intl
abtestingalpha Sep 3, 2024
6e479a4
Adds missed fields
abtestingalpha Sep 4, 2024
bfd4ebe
Few more missed fields
abtestingalpha Sep 4, 2024
589b257
Adds LanguageSelector
abtestingalpha Sep 4, 2024
2723c34
Adds LanguageSelector to mobile
abtestingalpha Sep 4, 2024
d1e45df
TranslatedText component for toast helper utils
abtestingalpha Sep 4, 2024
c51e319
Landing page
abtestingalpha Sep 4, 2024
8d60e51
Persists language in local storage
abtestingalpha Sep 4, 2024
d53bec9
Missed fields in Pools
abtestingalpha Sep 4, 2024
c22fa0a
Toasts
abtestingalpha Sep 4, 2024
7fa89b6
Fix hook rule issue
abtestingalpha Sep 4, 2024
e86cd9a
Merge branch 'master' into fe/next-intl
abtestingalpha Sep 4, 2024
6f7dd1c
Adds Locale to RainbowKitProvider
abtestingalpha Sep 4, 2024
df9a9e3
Updates LanguageSelector
abtestingalpha Sep 4, 2024
19563c4
Hover & open
abtestingalpha Sep 4, 2024
c48c1d3
Add support for non-Roman languages (Japanese example)
abtestingalpha Sep 4, 2024
62c106a
Fix message
abtestingalpha Sep 4, 2024
80e2675
Adds more language examples, removes lorem-ipsum
abtestingalpha Sep 4, 2024
c096293
Updating es.json (#3102)
Defi-Moses Sep 5, 2024
3c81524
Adds script to check translation keys to ensure they match en-US.json
abtestingalpha Sep 5, 2024
6db2c34
Lints
abtestingalpha Sep 5, 2024
bfe6076
Defaults to en-US locale messages of translation is missing
abtestingalpha Sep 5, 2024
68cabe6
Updates lock
abtestingalpha Sep 5, 2024
2e91732
Adds instructions to add new language
abtestingalpha Sep 5, 2024
817cc5d
Adds translations to dependency array
abtestingalpha Sep 5, 2024
65f5f6c
Merge branch 'master' into fe/next-intl
abtestingalpha Sep 6, 2024
d43cfb9
Merge branch 'master' into fe/next-intl
abtestingalpha Sep 6, 2024
4f7d127
Merge branch 'master' into fe/next-intl
abtestingalpha Sep 6, 2024
2c9ef80
Update french translation (#3110)
Defi-Moses Sep 6, 2024
6182798
Updating Arabic translation (#3112)
Defi-Moses Sep 9, 2024
f05ecc3
Merge branch 'master' into fe/next-intl
abtestingalpha Sep 9, 2024
4ac7e4e
Hides languages without finalized translations
abtestingalpha Sep 9, 2024
c23c358
Merge branch 'master' into fe/next-intl
abtestingalpha Sep 9, 2024
b11556b
Coderabbit nits
abtestingalpha Sep 9, 2024
3524cee
Merge branch 'master' into fe/next-intl
abtestingalpha Sep 9, 2024
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
43 changes: 43 additions & 0 deletions packages/synapse-interface/.eslintrc-i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const { ignorePatterns } = require('./.eslintrc')

module.exports = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
plugins: ['i18next'],
ignorePatterns: [
'pages/lifi/index.tsx',
'components/Maintenance/example/EcotoneForkUpgrade.tsx',
'pages/_app.tsx',
],
rules: {
// Enable the i18next rule
'i18next/no-literal-string': 'error',

// Disable unrelated rules
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'prefer-arrow/prefer-arrow-functions': 'off',
'import/order': 'off',
'prefer-const': 'off',
'jsdoc/newline-after-description': 'off',
'no-duplicate-imports': 'off',
eqeqeq: 'off',
'no-return-await': 'off',
'object-shorthand': 'off',
'prettier/prettier': 'off',
'no-redeclare': 'off',
radix: 'off',
'jsdoc/check-alignment': 'off',
'no-undef-init': 'off',
},
// Ignore all other plugins and extends
extends: [],
}
170 changes: 87 additions & 83 deletions packages/synapse-interface/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,31 +64,31 @@ This guide explains how to use the Maintenance feature to pause a chain or bridg
## How it works

There are a few maintenance components implemented around the Synapse Interface Webapp:

1. Banner - located at the top of the page.
2. Countdown Progress Bar - located at the top of Bridge / Swap cards.
3. Warning Message - located below the input UI in Bridge / Swap cards.

NOTE: Currently, the Synapse Widget implements the Countdown Progress Bar and Warning Message displayed in the Bridge Widget, but not the Banner.

These components ingest data fetched from the following JSON files:

- [Pause Chains JSON](https://github.com/synapsecns/sanguine/blob/master/packages/synapse-interface/public/pauses/v1/paused-chains.json)
- [Pause Bridge Modules JSON](https://github.com/synapsecns/sanguine/blob/master/packages/synapse-interface/public/pauses/v1/paused-bridge-modules.json)


To control when the Banner, Countdown Progress Bar, and Warning Message components are displayed, update the [Pause Chains JSON](https://github.com/synapsecns/sanguine/blob/master/packages/synapse-interface/public/pauses/v1/paused-chains.json).

To specify which bridge modules (SynapseRFQ, SynapseBridge, or SynapseCCTP) are paused, update the [Pause Bridge Modules JSON](https://github.com/synapsecns/sanguine/blob/master/packages/synapse-interface/public/pauses/v1/paused-bridge-modules.json).


After updating the proper JSON files, the following steps must be taken to ensure the production webapp reflects the changes made:

1. Merge the new branch into `master`
2. Merge `master` branch into `fe-release` branch

After Step 1 is completed, the [Github Pages](https://github.com/synapsecns/sanguine/deployments/github-pages) must finish building for the respective branch to take effect on the production webapp.

Although completing Step 1 will already reflect changes in the webapp, Step 2 is required in the slim chance that the github API is down, so that the production webapp can use the local JSON files as a reliable backup data source.


## Chain Pause

You can pause the Bridge and Swap functionalities on specific chains using their chainIds. Pauses can be applied independently to Bridge or Swap functions, or to both simultaneously.
Expand All @@ -97,7 +97,6 @@ For Bridge functionality, you can specify the origin and destination chainIds to

Additionally, you can control which components are displayed during the pause event.


### Chain Pause Props

`id`
Expand Down Expand Up @@ -145,77 +144,76 @@ Boolean indicating whether to hide Warning Message in Bridge or Swap card.
`disableCountdown`
Boolean indicating whether to hide Countdown Progress Bar.


### Example

`paused-chains.json`
```tsx
[
// Bridge Pause
{
"id": "base-chain-pause",
"pausedFromChains": [8453],
"pausedToChains": [8453],
"pauseBridge": true,
"pauseSwap": false,
"startTimePauseChain": "2024-04-12T17:41:00Z",
"endTimePauseChain": null,
"startTimeBanner": "2024-04-12T04:40:00Z",
"endTimeBanner": null,
"inputWarningMessage": "Base bridging is paused until maintenance is complete.",
"bannerMessage": "Base bridging is paused until maintenance is complete.",
"progressBarMessage": "Base maintenance in progress",
"disableBanner": false,
"disableWarning": false,
"disableCountdown": false
},
{
"id": "ecotone-fork-pause",
"pausedFromChains": [10, 8453],
"pausedToChains": [10, 8453],
"pauseBridge": true,
"pauseSwap": false,
"startTimePauseChain": "2024-03-13T23:35:00Z",
"endTimePauseChain": "2024-03-14T00:25:00Z",
"startTimeBanner": "2024-03-13T23:20:00Z",
"endTimeBanner": "2024-03-14T00:25:00Z",
"inputWarningMessage": "",
"bannerMessage": "Optimism + Base Bridging will be paused 10 minutes ahead of Ecotone (March 14 00:00 UTC, 20:00 EST). Will be back online shortly following the network upgrade.",
"progressBarMessage": "Ecotone Fork maintenance in progress",
"disableBanner": false,
"disableWarning": true,
"disableCountdown": false
},
// Swap Pause
{
"id": "arbitrum-swap-pause",
"pausedFromChains": [42161],
"pausedToChains": [42161],
"pauseBridge": false,
"pauseSwap": true,
"startTimePauseChain": "2024-03-13T23:35:00Z",
"endTimePauseChain": "2024-03-14T00:25:00Z",
"startTimeBanner": "2024-03-13T23:20:00Z",
"endTimeBanner": "2024-03-14T00:25:00Z",
"inputWarningMessage": "Swapping on Arbitrum is paused until maintenance is complete.",
"bannerMessage": "Swapping on Arbitrum is paused until maintenance is complete.",
"progressBarMessage": "Arbitrum maintenance in progress",
"disableBanner": false,
"disableWarning": false,
"disableCountdown": false
}
]
```

```json
[
// Bridge Pause
{
"id": "base-chain-pause",
"pausedFromChains": [8453],
"pausedToChains": [8453],
"pauseBridge": true,
"pauseSwap": false,
"startTimePauseChain": "2024-04-12T17:41:00Z",
"endTimePauseChain": null,
"startTimeBanner": "2024-04-12T04:40:00Z",
"endTimeBanner": null,
"inputWarningMessage": "Base bridging is paused until maintenance is complete.",
"bannerMessage": "Base bridging is paused until maintenance is complete.",
"progressBarMessage": "Base maintenance in progress",
"disableBanner": false,
"disableWarning": false,
"disableCountdown": false
},
{
"id": "ecotone-fork-pause",
"pausedFromChains": [10, 8453],
"pausedToChains": [10, 8453],
"pauseBridge": true,
"pauseSwap": false,
"startTimePauseChain": "2024-03-13T23:35:00Z",
"endTimePauseChain": "2024-03-14T00:25:00Z",
"startTimeBanner": "2024-03-13T23:20:00Z",
"endTimeBanner": "2024-03-14T00:25:00Z",
"inputWarningMessage": "",
"bannerMessage": "Optimism + Base Bridging will be paused 10 minutes ahead of Ecotone (March 14 00:00 UTC, 20:00 EST). Will be back online shortly following the network upgrade.",
"progressBarMessage": "Ecotone Fork maintenance in progress",
"disableBanner": false,
"disableWarning": true,
"disableCountdown": false
},
// Swap Pause
{
"id": "arbitrum-swap-pause",
"pausedFromChains": [42161],
"pausedToChains": [42161],
"pauseBridge": false,
"pauseSwap": true,
"startTimePauseChain": "2024-03-13T23:35:00Z",
"endTimePauseChain": "2024-03-14T00:25:00Z",
"startTimeBanner": "2024-03-13T23:20:00Z",
"endTimeBanner": "2024-03-14T00:25:00Z",
"inputWarningMessage": "Swapping on Arbitrum is paused until maintenance is complete.",
"bannerMessage": "Swapping on Arbitrum is paused until maintenance is complete.",
"progressBarMessage": "Arbitrum maintenance in progress",
"disableBanner": false,
"disableWarning": false,
"disableCountdown": false
}
]
```

## Bridge Module Pause

You can pause a specific bridge module on a given chain. Currently, there are the following bridge modules:

- SynapseRFQ
- SynapseCCTP
- SynapseBridge


### Bridge Module Pause Props

`chainId`
Expand All @@ -224,27 +222,33 @@ Chain ID of Chain to pause specific bridge module.
`bridgeModuleName`
Accepts 'SynapseRFQ', 'SynapseBridge', 'SynapseCCTP', or 'ALL'. If selecting 'ALL', all bridge modules will be paused for respective chainId.


### Example

`paused-bridge-modules.json`
```tsx
[
{
"chainId": 42161,
"bridgeModuleName": "ALL"
},
{
"chainId": 10,
"bridgeModuleName": "SynapseRFQ"
},
{
"chainId": 10,
"bridgeModuleName": "SynapseCCTP"
},
{
"chainId": 8453,
"bridgeModuleName": "SynapseBridge"
}
]

```json
[
{
"chainId": 42161,
"bridgeModuleName": "ALL"
},
{
"chainId": 10,
"bridgeModuleName": "SynapseRFQ"
},
{
"chainId": 10,
"bridgeModuleName": "SynapseCCTP"
},
{
"chainId": 8453,
"bridgeModuleName": "SynapseBridge"
}
]
```

## Adding a New Language

1. Update `next.config.js` with the new locale code.
2. Update `LanguageSelector` component to include the new locale.
3. Update `/messages/{locale.json}` with the new locale's translations. The keys in this should match `en-US.json`. See some of the other language files for reference.
abtestingalpha marked this conversation as resolved.
Show resolved Hide resolved
12 changes: 8 additions & 4 deletions packages/synapse-interface/components/Activity/Activity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import _ from 'lodash'
import Fuse from 'fuse.js'
import { useAccount } from 'wagmi'
import { type Address } from 'viem'
import { useTranslations } from 'next-intl'

import { type Chain } from '@/utils/types'
import { useTransactionsState } from '@/slices/transactions/hooks'
import { usePortfolioState } from '@/slices/portfolio/hooks'
Expand Down Expand Up @@ -50,30 +52,32 @@ export const Activity = ({ visibility }: { visibility: boolean }) => {
} else return null
}, [isMasqueradeActive, masqueradeAddress, address])

const t = useTranslations('Activity')

return (
<div
data-test-id="activity"
className={`${visibility ? 'block' : 'hidden'}`}
>
{!viewingAddress && (
<div className="text-secondary">
Your pending and recent transactions will appear here.
{t('Your pending and recent transactions will appear here')}
</div>
)}

{viewingAddress && isLoading && (
<div className="text-secondary">Loading activity...</div>
<div className="text-secondary">{t('Loading activity')}...</div>
)}

{viewingAddress && !isLoading && !hasHistoricalTransactions && (
<div className="text-secondary">
No transactions in last 30 days.
{t('No transactions in last 30 days.')}
<UserExplorerLink connectedAddress={viewingAddress} />
</div>
)}

{viewingAddress && !isLoading && hasHistoricalTransactions && (
<ActivitySection title="Recent">
<ActivitySection title={t('Recent')}>
{userHistoricalTransactions &&
filteredHistoricalTransactions
.slice(0, isSearchInputActive ? 100 : 6)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Address } from 'viem'
import { useTranslations } from 'next-intl'

import { shortenAddress } from '@/utils/shortenAddress'
import { convertUnixTimestampToMonthAndDate } from '@/utils/time'
import { isTimestampToday } from '@/utils/time'
Expand Down Expand Up @@ -26,6 +28,8 @@ export const Completed = ({

const isDestinationValid: boolean = isValidAddress(destinationAddress)

const t = useTranslations('Completed')

return (
<div
data-test-id="completed"
Expand All @@ -40,12 +44,14 @@ export const Completed = ({
`}
>
{isDestinationValid && !isDestinationSender && (
<div>to {shortenAddress(destinationAddress)} </div>
<div>
{t('to')} {shortenAddress(destinationAddress)}{' '}
</div>
)}
{isToday ? (
<div>Today</div>
<div>{t('Today')}</div>
) : (
<div>{formattedTime ? formattedTime : 'Completed'}</div>
<div>{formattedTime ? formattedTime : t('Completed')}</div>
)}
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from 'react'
import { useTranslations } from 'next-intl'

import { TransactionStatus } from '../Transaction'
import ProcessingIcon from '@/components/icons/ProcessingIcon'

Expand All @@ -9,6 +11,8 @@ export const EstimatedDuration = ({
timeRemaining: number
transactionStatus: TransactionStatus
}) => {
const t = useTranslations('Time')

return (
<div
data-test-id="estimated-duration"
Expand All @@ -17,15 +21,15 @@ export const EstimatedDuration = ({
{timeRemaining >= 0 ? (
<React.Fragment>
<div>
{timeRemaining} - {timeRemaining + 1} min
{timeRemaining} - {timeRemaining + 1} {t('min')}
</div>
{transactionStatus !== TransactionStatus.PENDING_WALLET_ACTION && (
<ProcessingIcon className="fill-[#343036] mt-0.5" />
)}
</React.Fragment>
) : (
<React.Fragment>
<div>Waiting... </div>
<div>{t('Waiting')}... </div>
<ProcessingIcon className="fill-[#343036] mt-0.5" />
</React.Fragment>
)}
Expand Down
Loading
Loading