Skip to content

Conversation

@gabitoesmiapodo
Copy link

@gabitoesmiapodo gabitoesmiapodo commented Aug 28, 2025

Summary

First, sorry for the huge PR... this involved changing a lot of files, mainly because I had to add Lingui macros to practically every string in the app.

This PR is related to RFP: Internationalization setup - Grant Application - Internationalization setup for swap.cow.fi

Deployed preview available at: https://cowswap-i18n.vercel.app/

Detailed setup and workflow documentation: Internationalization doc (gist)

Details:

Internationalization (i18n) Implementation

This PR introduces full internationalization support to the CowSwap app (/apps/cowswap-frontend)

Files in other apps or sites in the monorepo were not modified, unless unavoidable, e.g. the footer was not updated because other apps do not yet support i18n and this could introduce some problems. As a result, some text might still remain in English, this is expected.

The bulk of the changes were mainly adding Lingui macros to user-facing strings, and adapting the components where needed if Lingui's constraints made using available implementations impossible (e.g.: top-level strings are a no-go for Lingui).

Translations were performed by Crowdin (automatic translation), so they're not perfect. That will need more work from an expert in such matters.

Main changes

  • Lingui upgrade: Updated to the latest version and fixed all incompatibilities.

  • ESLint rules: Added rules for Lingui usage to prevent future issues.

  • Localization coverage: Ensured all user-facing strings in cowswap-frontend are marked for translation.

  • Languages enabled: Added support for es-ES (Spanish) and ru-RU (Russian). Russian was chosen to validate UI handling of longer/non-Latin text.

  • Language switcher: Implemented a functional and styled dropdown to select languages. Language names are not translated.

  • Automatic detection: Detects browser locale and defaults to English when unsupported.

  • Persistence: Remembers user language selection per browser, without overwriting it with auto-detection.

  • Crowdin integration:

    • Added crowdin.yml to the app.
    • Test project created and connected to GitHub (CowSwap will have to create and configure their own, documentation is available)
    • Automatic sync of en-US.po changes to translation files.
    • Sync runs automatically when pushing to a designated branch or manually.
  • Feature flag: REACT_APP_LINGUI_INTERNATIONALIZATION controls hiding / showing the system.

  • Stable URLs regardless of selected language.

Screenshots:

image image image
Aug-28-2025.18-28-20.mp4

To Test

  1. REACT_APP_LINGUI_INTERNATIONALIZATION=true should be added to see the dropdown
  2. Also test removing the variable, the dropdown should disappear.
  3. Test switching languages, strings should change (except where not applicable, as noted above).
  4. A visual inspection for localized text breaking the layout should also be performed.

gabitoesmiapodo and others added 30 commits August 14, 2025 17:54
* Updated lingui dependencies to the latest versions.
* Added eslint-plugin-lingui to prevent some issues.
* Fixed problems introduced when updated lingui dependencies.
* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)

* Update source file en-US.po
* Update source file en-US.po

* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)
* New translations en-us.po (Spanish)

* New translations en-us.po (Spanish)
* feat: add basic languages dropdown

* feat: add languages dropdown with labels and flags

* feat: store language when language is switched

* chore: remove deprecated functions

* fix: top menu not updating

* fix: strings not updating when language changes

* fix: strings not updating when language changes

* fix: remove lingui usage from footer
* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)

* Update source file en-US.po

* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)

* Update apps/cowswap-frontend/src/locales/ru-RU.po

Co-authored-by: Copilot <[email protected]>

* Update apps/cowswap-frontend/src/locales/es-ES.po

Co-authored-by: Copilot <[email protected]>

* Update apps/cowswap-frontend/src/locales/ru-RU.po

Co-authored-by: Copilot <[email protected]>

---------

Co-authored-by: Copilot <[email protected]>
* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)

* Update source file en-US.po

* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)
* Update source file en-US.po

* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)

* Update source file en-US.po

* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)
* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)

* Update source file en-US.po

* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)
@gabitoesmiapodo
Copy link
Author

Hey @elena-zh , thanks for the new review. We're getting there, I think.

Also thanks for the testing accounts, they were very useful.

I worked on the issues you sent, and also merged the latest changes from develop, fixed conflicts, added some new localizations, etc. It's somewhat hard to keep the localizations up to date when the app's text is constantly being modified (which is inevitable, this PR modified pretty much the whole app), but oh well... I hope I didn't miss any new localizations.

About the issues:

These have some comments from me

I noticed, that Limit order statuses were expanded.

I reverted this to the previous state.

(continuation of the p.3): since the status width was increased, it increased the 'parts' column width on the TWAP page, and it does not look good now. Besides. 'partially filled' status is not fixed on the TWAP page

I'm pretty sure this particular piece of code is shared across the app, so it should reverted here as well (please let me know if it isn't).

However, it would be great to use another approach here: ideally it should be flexible enough to handle arbitrary lengths of text for the label (with some limits)

I'm having some trouble with this. Every row is a separate entity, unaware of what the other rows are showing and their individual columns' width. So if I change a column's width or any properties, they change for all of them.

So: all the widths are pre-set, and there's already a min / max width for all the columns except the last one (it's the way it was originally implemented). If I modify this particular column's width to something more "generous", this is what happens (columns min/max width varies more, so each row is visibly different now).

SCR-20251021-lufv

I think some possible solutions to this could be:

  • Use an actual HTML table instead of divs. This could probably fix the width's issue, but would require some major refactoring, and would introduce some other issues I'm sure... I wouldn't go this way unless extremely necessary.
  • Maybe tweak the design a little so it doesn't matter if words are too long, but still inform the user using colors. Maybe an icon + tooltip? Icon + text (without the enclosing badge-like div)?

Anyways, this is what I could come up with modifying as little code as possible. It works, but it's brittle: extremely long words could break it or make it look funny:

SCR-20251021-lyka

TWAP: part duration tooltip: still there are some special symbols in it
Same for the TWAP total duration:
Low price on the Limit orders: still there are special symbpols in it:

Fixed. Sometimes Crowdin does that (breaking tags in translations), I don't know why.

Swap and bridge orders, Confirm modal: there is a Route field, and the tooltip contains info about stops. 'Stop' word should be translated

Fixed. Crowdin didn't translate some of the words.

It would be nice to translate an error when I reject a connection from the wallet (or connection fails):

This error message is coming from the wallet, I tried rejecting the connection with a few different ones and the message changes. In other words: we can't translate it. Also, it shows different messages for different errors. Maybe it can be handled somehow, but I'm not sure about the way to do that.

These should be fixed, no comments:

Hooks section appears to be shifted for a swap and bridge order details:

Fixed

Order type appears to be translated to Spanish in the Account modal

Fixed

Swap confirm modal does not look good in a mobile view + scrollbar appears at the bottom

Fixed

Swap and bridge: route not supported is not translated

Fixed

'Approve' is still not transalted

Fixed

Swap and bridge orders: " view on..' is not translated

Fixed

Notifications panel name is still not translated

Fixed

* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)

* Update source file en-US.po

* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)

* Update source file en-US.po

* New translations en-us.po (Spanish)

* New translations en-us.po (Russian)
@elena-zh
Copy link
Contributor

Hey @gabitoesmiapodo ,
thank you for explanation and all the fixes you did.

I've done another test round, and here are some more notpicks that I've noticed:

  1. 'at least'/'at most'/'to/ on the Cancel modal is not translated
cancel at least and at most cancel buy order
  1. Swap and Bridge details: 'est' (estimated) in the Est.bridging time' is not translated
est
  1. Could you please check why there is an unnecessary space when translated to Russian in the 'Selling ETH not supported' banner?
exc space
  1. There is a 'Nonce' field that is not translated to Russian (but is translated to Spanish). Could you please check why it is so?
nonce miss translation
  1. Lock screen on the Swap form: when translated to Russian, the image gets expanded and looks like truncated one. Could you please fix it?
truncated should be
  1. (not fixed from the previous comment): Could you please check why the 'Surplus' tooltip has 2 periods in the end?
surp
  1. Could you please check why 'Signing' status looks good in the descktop mode, but when I reduce the screen width the status's width is also reduced?
image image
  1. Frankly, I don't like the decision to move 'Quote refresh in' to the left and glue it to the modal name. Now the timer looks abandoned :(
quote refresh Why not moving it to here? image
  1. Could you please check why these numbers are shifted to another line on the confirm modal?
image

As far as I can see, there should be enough space to display a longer value
can be longer

Thank you

@gabitoesmiapodo
Copy link
Author

Hey @elena-zh , here are the fixes.

'at least'/'at most'/'to/ on the Cancel modal is not translated

Added the new translations.

Swap and Bridge details: 'est' (estimated) in the Est.bridging time' is not translated

Crowdin missed that, so I made it translate it.

Could you please check why there is an unnecessary space when translated to Russian in the 'Selling ETH not supported' banner?

There was an issue with the way I placed the localization macros and some hardcoded spaces, let me know if it's better now.

There is a 'Nonce' field that is not translated to Russian (but is translated to Spanish). Could you please check why it is so?

Another Crowdin miss, probably didn't know what word to use (and probably still doesn't).

Lock screen on the Swap form: when translated to Russian, the image gets expanded and looks like truncated one. Could you please fix it?

Should be fixed.

not fixed from the previous comment): Could you please check why the 'Surplus' tooltip has 2 periods in the end?

I removed the period from the end of the sentence, but it seems that's the way the browser is rendering the date in Russian?

English is February 2023 + the period at the end.

Spanish is febrero de 2023 + the period at the end.

And Russian февраль 2023 г. + the period at the end. According to ChatGPT, that final г. is an abbreviation of год (sorry, I know nothing about Russian), and that's how the browser localizes the date.

But anyways, I removed the period, it'll only show up in Russian because of the abbreviation.

Could you please check why 'Signing' status looks good in the descktop mode, but when I reduce the screen width the status's width is also reduced?

Yeah, the wrapper changes width but also there's an extra icon there so if the word doesn't fit it breaks. That's why I suggested maybe tweaking the design a bit is the best option here.

The best I could do for now is making the browser break words more gracefully using hypens.

Frankly, I don't like the decision to move 'Quote refresh in' to the left and glue it to the modal name. Now the timer looks abandoned :(

Yep, our weekly "the new fix is also the new bug" contest. It should be aligned to the right now.

Could you please check why these numbers are shifted to another line on the confirm modal?

Fixed. Hopefully no regressions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants