Js-lingui: Allow escaping placeholders

Created on 19 Feb 2019  ยท  7Comments  ยท  Source: lingui/js-lingui

Describe the bug

Both react FilePond and lingui.js use {} chars to mark variables.
When you try to add FilePonf label for translations you get an error because lingui expect you will pass a value of the variable, but it actually FilePond's variable.

To Reproduce
Steps to reproduce the behavior, possibly with minimal code sample, e.g:

import { t } from '@lingui/macro';
import { I18n } from '@lingui/react';
import { FilePond } from 'react-filepond';

export default function App() {
   return (<I18n>
        {({ i18n }) => (<FilePond
                  โ€ฆ
                  labelMaxFileSize={i18n._(t`Maximum file size is {filesize}`)} />))}
        </I18n>);
}

You will get TypeError: Cannot read property 'filesize' of undefined โ€” it came from /node_modules/@lingui/core/cjs/core.development.js:134. I suppose that lingui.js think that filesize is lingui.js variable and expect filesize value should be passed. But it's should be passed by FilePhond.

Expected behavior
It would be nice to escape {} somehow.
I have tried / and // but I either get an error, either it just doesn't translate it.

Additional context
Add any other context about the problem here.

  • jsLingui version lingui --version 1.4.5
  • Babel version npm list babel-core
$ npm list babel-core
[email protected] /Users/silentimp/Work/instapro-client
โ””โ”€โ”ฌ [email protected]
  โ””โ”€โ”€ [email protected] 
  • Your Babel config (e.g. .babelrc) or framework you use (Create React App, Meteor, etc.)
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": false,
        "debug": false,
        "useBuiltIns": "usage",
        "targets": {
          "browsers": [">0.2%", "not dead", "not ie < 11", "not op_mini all"]
        }
      }
    ],
    "next/babel"
  ],
  "plugins": ["macros"]
}
๐Ÿžbug ๐Ÿ“ฆ cli ๐Ÿ“ฆ macro

All 7 comments

LinguiJS uses ICU MessageFormat. Could you please try escape argument using apostrophes?

Maximum file size is '{filesize}'

@tricoder42 I have tried to do it this way:

import { t } from '@lingui/macro';
import { I18n } from '@lingui/react';
import { FilePond } from 'react-filepond';

export default function App() {
   return (<I18n>
        {({ i18n }) => (<FilePond
                  โ€ฆ
                  labelMaxFileSize={i18n._(t`Maximum file size is '{filesize}'`)} />))}
        </I18n>);
}

After extractions I get inside message.json:

โ€ฆ
  "Maximum file size is '{filesize}'": "Maximum file size is '{filesize}'",
  "Maximum total file size is '{filesize}'": "Maximum total file size is '{filesize}'",
โ€ฆ

But I still get an error:

ร—
TypeError: Cannot read property 'filesize' of undefined
ctx
./node_modules/@lingui/core/cjs/core.development.js:134
  131 | var formatters = defaultFormats(language, locales, languageData, formats);
  132 | 
  133 | var ctx = function ctx(name, type, format) {
> 134 |   var value = values[name];
  135 |   var formatted = formatters[type](value, format);
  136 |   var message = isFunction(formatted) ? formatted(ctx) : formatted;
  137 |   return Array.isArray(message) ? message.join("") : message;

โ€ฆ

Looks like this is present in the newer version of messageformat-parser but not in version 2.0.0 that @lingui/core uses.

Here's the messageformat-parser changelog

Actually, I think this is an actual non-production bug with how the lingui compiler parses escaping characters that would exist even after upgrading to [email protected].

In [email protected], using \\ instead of ' should escape the curly braces
(i.e. Maximum file size is \\{filesize\\}).

In non-production env, messages that are compiled to strings are compiled twice, once on I18n.load and again on I18n._.

Since the messageformat-parser removes the escape characters, the redundant parsing causes the escape characters to be ignored.

parse(parse('Maximum file size is \\{filesize\\}'))
โ†“โ†“โ†“โ†“โ†“โ†“โ†“โ†“
parse('Maximum file size is {filesize}')
โ†“โ†“โ†“โ†“โ†“โ†“โ†“โ†“
compiled message function that treats 'filesize' as an argument

A solution would be to try to avoid compiling messages twice, either by always compiling to a functiion instead of sometimes a string or avoiding compiling on I18n._ if this.messages[id] exists.

In fact, I was wrong earlier; [email protected] actually contains support for ' as an escape character already which might explain the behavior in #421.

@tricoder42 This is fixed in v3. Should this be closed?

@hjylewis Yeah, good point! ๐Ÿ‘

Was this page helpful?
0 / 5 - 0 ratings

Related issues

landsman picture landsman  ยท  5Comments

benbender picture benbender  ยท  5Comments

charliedavison picture charliedavison  ยท  3Comments

smeevil picture smeevil  ยท  3Comments

MartinCerny-awin picture MartinCerny-awin  ยท  6Comments