Home > Software engineering >  How to add a partial style for a i18n translation?
How to add a partial style for a i18n translation?

Time:02-02

I want an elegant solution for add styling like bold, italic, color for only a part of a translation.

Example

Let say that I have this i18n translation:

'my-page.confim-customer.popup.warning': 'All customer files must be authorized by the customer himself, please be sure to invite the customer to scan this QR code.'

Now i want that the words "must be authorized by the customer himself" will be in bold and in yellow. (Design requirement)

What can I do?

Solution 1 - Split in i18n

I can simply split the translation to three parts in i18n file:

// i18n/en.js
'my-page.confim-customer.popup.warning.part1': 'All customer files'
'my-page.confim-customer.popup.warning.part2': 'must be authorized by the customer himself,'
'my-page.confim-customer.popup.warning.part3': 'please be sure to invite the customer to scan this QR code.'

and then apply the css i want only on the "part2".

// MyComponent.jsx
const first = i18n.t('my-page.confim-customer.popup.warning.part1');
const second = i18n.t('my-page.confim-customer.popup.warning.part2');
const thrid = i18n.t('my-page.confim-customer.popup.warning.part3');

return (
  <>
    <div>
      {first} 
      <span className="bold yellow">{second}</span>
      {thrid}
    </div>
  </>
);

Pros

  • It works

Cons

  • Polute the i18n files with lots of partial string for each lines.
  • When change is required it is a hassel to change the view and translation

Solution 2 - Split in code

I keep i18n in the same translation but I add seprator in it (let say $#$):

'my-page.confim-customer.popup.warning': 'All customer files $#$must be authorized by the customer himself,$#$ please be sure to invite the customer to scan this QR code.'

And then in my component i split it:

// MyComponent.jsx
const [first, second, thrid] = i18n.t('my-page.confim-customer.popup.warning').split('$#$')

return (
  <>
    <div>
      {first} 
      <span className="bold yellow">{second}</span>
      {thrid}
    </div>
  </>
);

Pros

  • It works
  • Offload the headache to javascirpt, keep the translation in one i18n key

Cons

  • Need to process the key before using it
  • When change is needed (let say we add a new seperator for a section to be italic), we need to alter the way we process the key and change the view to match. not dynamic.

Note

I'm looking for a vanilla solution, as I'm not working with React or a popular framework.

CodePudding user response:

i18n have special component Trans. There you can use any components inside your string like:

"test" : "All customer files <yelow>must be authorized by the customer himself,</yelow> please be sure to invite the customer to scan this QR code."

...


<Trans 
  i18nKey='test' 
  components={{ yelow: <span className="bold yellow"/> }}
/>

https://react.i18next.com/latest/trans-component

CodePudding user response:

The strings splitted into separate keys are extremely not translator-friendly. It would be hard for translators to provide quality translations since they need to know where each part is used just not to break the UI.

In addition, the translation for some languages likely will have a different word order. The situation is even more complicated in RTL languages.

So, it's definitely recommended to avoid such approaches with string splitting.

As a Vanilla JS solution that can work in your case, I would recommend the Lingui library.

In short, it allows developers to do the following thing by using the @lingui/macro package:

import { Trans } from "@lingui/macro"

<Trans>Read the <a href="/docs">docs</a>.</Trans>;

Then you can extract all your localizable texts to the .po or .json file by using the Lingui CLI.

Components and HTML tags are replaced with dummy indexed tags (<0></0>) which has several advantages:

  • both custom React components and built-in HTML tags are supported
  • change of component props doesn't break the translation
  • the message is extracted as a whole sentence (this seems to be obvious, but most i18n libs simply split the message into pieces by tags and translate them separately)

Further reading:

  • Related