Giter Club home page Giter Club logo

js-lingui's Introduction

Linguijs

🌍📖 A readable, automated, and optimized (3 kb) internationalization for JavaScript


Main Suite Release Workflow Testing Code Coverage PRs Welcome Join the community on Discord

Documentation · Quickstart · Example · Support · Contribute · License

Internationalization is the design and development of a product, application or document content that enables easy localization for target audiences that vary in culture, region, or language.

--- W3C Web Internationalization FAQ

Lingui is an easy yet powerful internationalization framework for global projects.

  • Clean and readable - Keep your code clean and readable, while the library uses battle-tested and powerful ICU MessageFormat under the hood.

  • Universal - Use it everywhere. @lingui/core provides the essential intl functionality which works in any JavaScript project while @lingui/react offers components to leverage React rendering.

  • Full rich-text support - Use React components inside localized messages without any limitation. Writing rich-text messages is as easy as writing JSX.

  • Powerful tooling - Manage the whole intl workflow using Lingui CLI. It extracts messages from source code, validates messages coming from translators and checks that all messages are translated before shipping to production.

  • Unopinionated - Integrate Lingui into your existing workflow. It supports message keys as well as auto-generated messages. Translations are stored either in JSON or standard PO files, which are supported in almost all translation tools.

  • Lightweight and optimized - Core library is only 1.5 kB gzipped, React components are an additional 1.3 kBs gzipped. That's less than Redux for a full-featured intl library.

  • Active community - Join us on Discord to discuss the latest development. At the moment, Lingui is the most active intl project on GitHub.

  • Compatible with react-intl - Low-level React API is very similar to react-intl and the message format is the same. It's easy to migrate an existing project.

Quickstart

Install

Tutorials

Plugins

If you're a react-intl user, check out a comparison of react-intl and Lingui.

Example

Short example how i18n looks with JSX:

import { Trans } from "@lingui/macro"

function App() {
  return (
   <Trans id="msg.docs" /* id is optional */>
     Read the <a href="https://lingui.dev">documentation</a>
     for more info.
   </Trans>
  )
}

Message from this component will be extracted in following format:

msgid "msg.docs"
msgstr "Read the <0>documentation</0> for more info."

For more example see the Examples directory.

Support

If you are having issues, please let us know.

  • Join us on Discord to chat with the community.
  • Ask questions on StackOverflow and mark it with Lingui tag.
  • If something doesn't work as documented, documentation is missing or if you just want to suggest a new feature, create an issue.

Contribute

Contribution to open-source project is everything from spreading the word, writing documentation to implement features and fixing bugs.

  • Do you use Lingui in production site? Let us know!
  • Have you seen any interesting talk or article about i18n? Share it!
  • Have you found a bug or do you want to suggest a new feature? Create an issue!
  • Do you want to improve the docs and write some code? Read the contributors guide and send a PR!

Contributors

This project exists thanks to all the people who contribute. [Contribute].

License

The project is licensed under the MIT license.

js-lingui's People

Contributors

andrii-bodnar avatar arcanis avatar aseerkt avatar bertg avatar bityog avatar bravo-kernel avatar capaj avatar dependabot-preview[bot] avatar edorivai avatar fredyc avatar j4hr3n avatar laszbalo avatar lingui-bot avatar lucasecdb avatar martin005 avatar martincerny-awin avatar michaelhoste avatar nakkamarra avatar orangain avatar pieterjanscheir avatar semoal avatar skovhus avatar snaptags avatar stovmascript avatar taozhou-glean avatar thekip avatar thibautre avatar thiefmaster avatar tricoder42 avatar vonovak avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

js-lingui's Issues

Fix default ignore pattern to work on Windows

I'm using create-react-app with react-app-rewired to enable making changes to webpack/babel without ejecting.

I've added the following config-overrides.js file (a react-app-rewired requirement):

module.exports = function override(config, env) {
	let babelLoader;

	const checkRule = rule => rule.loader && rule.loader.indexOf('babel-loader') > 0;

	config.module.rules.every(rule => {
		if (rule.oneOf) {
			babelLoader = rule.oneOf.find(checkRule);
		} else if (checkRule(rule)) {
			babelLoader = rule.loader;
		}
		return !babelLoader;
	});

	babelLoader.options.babelrc = true;
	return config
}

This make sure to load the .babelrc file with the needed presets:

{
  "plugins": [
    "syntax-dynamic-import"
  ],
  "env": {
    "test": {
      "plugins": [
        "dynamic-import-node"
      ]
    }
  },
  "presets": [
    "env",
    "react",
    "lingui-react"
  ]
}

While this approach is working, extract is failing with the following exception:

Extracting messages from source files:
C:\Development\partner_portal\client\config-overrides.js
C:\Users\ofirhe\AppData\Local\Yarn\config\global\node_modules\babel-core\lib\transformation\file\index.js:590
      throw err;
      ^

SyntaxError: C:/Development/partner_portal/client/node_modules/.bin/sha.js: Unexpected token, expected , (2:18)
  1 | #!/bin/sh
> 2 | basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
    |                   ^
  3 | 
  4 | case `uname` in
  5 |     *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
    at Parser.pp$5.raise (C:\Users\ofirhe\AppData\Local\Yarn\config\global\node_modules\babylon\lib\index.js:4454:13)
    at Parser.pp.unexpected (C:\Users\ofirhe\AppData\Local\Yarn\config\global\node_modules\babylon\lib\index.js:1761:8)
    at Parser.pp.expect (C:\Users\ofirhe\AppData\Local\Yarn\config\global\node_modules\babylon\lib\index.js:1749:33)
    at Parser.pp$3.parseCallExpressionArguments (C:\Users\ofirhe\AppData\Local\Yarn\config\global\node_modules\babylon\lib\index.js:3564:12)
    at Parser.pp$3.parseSubscripts (C:\Users\ofirhe\AppData\Local\Yarn\config\global\node_modules\babylon\lib\index.js:3533:31)
    at Parser.pp$3.parseExprSubscripts (C:\Users\ofirhe\AppData\Local\Yarn\config\global\node_modules\babylon\lib\index.js:3504:15)
    at Parser.pp$3.parseMaybeUnary (C:\Users\ofirhe\AppData\Local\Yarn\config\global\node_modules\babylon\lib\index.js:3474:19)
    at Parser.pp$3.parseExprOps (C:\Users\ofirhe\AppData\Local\Yarn\config\global\node_modules\babylon\lib\index.js:3404:19)
    at Parser.pp$3.parseMaybeConditional (C:\Users\ofirhe\AppData\Local\Yarn\config\global\node_modules\babylon\lib\index.js:3381:19)
    at Parser.pp$3.parseMaybeAssign (C:\Users\ofirhe\AppData\Local\Yarn\config\global\node_modules\babylon\lib\index.js:3344:19)

Expected:
While I think this exception should be addressed, I think it would also be beneficial to allow specifying the files to include/exclude from the extraction process

[DX] Would love to see t() directly injected by WithI18n-hoc

Hey,

I'm playing with lingui at the moment and I'm pleased so far ;) Just two little DX-Items to reason about:

a) is there is any reason not to inject the method t() directly into the wrapped component by using WithI18n()-hoc? Would save the devs some repitive keystrokes!

b) I would love to see the naming of WithI18n changed to withI18n. Most devs are using capital first letters for classes which can be instantiated and most hocs are starting lowercase. One thing less to remember about.

Cheers & thanks

Error on empty translation in fallbackLanguage

Empty translation ("translation": "",) in language set as fallbackLanguage throws

if (input.charCodeAt(peg$currPos) === 123) {
             ^

TypeError: Cannot read property 'charCodeAt' of undefined

RelativeDateTime component

First off, thanks for this project. It's pretty much exactly what I wished for while being significantly smaller than other implementations.

const date = new Date(new Date() - 30 * 1000)
magic(date) -> '30 seconds ago'

Is there any way (now or planned) to format a date as a relative time string? Or is there another preferred way of dealing with these - I am thinking about a custom component and translation messages?

Or to word it differently, if you think that its best dealt with with a custom component, would you be interested to have something like that in the docs?

lingui-cli extract

Hi,
I have upgraded the package since last time, here is my config:

├─┬ [email protected]
│ ├── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
├─┬ [email protected]
├─┬ [email protected]
│ └── [email protected]
├── [email protected]

But I encounter a problem when I do lingui extract, Unexpected token.
The code is fine and works when I yarn build it or yarn start it

yarn lingui v0.27.5
$ "/home/lfdmr/Dev/test/web_frontend/node_modules/.bin/lingui" "extract"

/home/lfdmr/Dev/test/web_frontend/node_modules/lingui-cli/node_modules/babel-core/lib/transformation/file/index.js:590
      throw err;
      ^

SyntaxError: /home/lfdmr/Dev/test/web_frontend/src/App1/components/App.js: Unexpected token (6:2)
  4 | 
  5 | const App = () => (
> 6 |   <h1><Trans>Welcome App 1!</Trans></h1>
    |   ^
  7 | )
  8 | 
  9 | export default App
    at Parser.pp$5.raise (/home/lfdmr/Dev/test/web_frontend/node_modules/lingui-cli/node_modules/babylon/lib/index.js:4454:13)
    at Parser.pp.unexpected (/home/lfdmr/Dev/test/web_frontend/node_modules/lingui-cli/node_modules/babylon/lib/index.js:1761:8)
    at Parser.pp$3.parseExprAtom (/home/lfdmr/Dev/test/web_frontend/node_modules/lingui-cli/node_modules/babylon/lib/index.js:3750:12)
    at Parser.pp$3.parseExprSubscripts (/home/lfdmr/Dev/test/web_frontend/node_modules/lingui-cli/node_modules/babylon/lib/index.js:3494:19)
    at Parser.pp$3.parseMaybeUnary (/home/lfdmr/Dev/test/web_frontend/node_modules/lingui-cli/node_modules/babylon/lib/index.js:3474:19)
    at Parser.pp$3.parseExprOps (/home/lfdmr/Dev/test/web_frontend/node_modules/lingui-cli/node_modules/babylon/lib/index.js:3404:19)
    at Parser.pp$3.parseMaybeConditional (/home/lfdmr/Dev/test/web_frontend/node_modules/lingui-cli/node_modules/babylon/lib/index.js:3381:19)
    at Parser.pp$3.parseMaybeAssign (/home/lfdmr/Dev/test/web_frontend/node_modules/lingui-cli/node_modules/babylon/lib/index.js:3344:19)
    at Parser.pp$3.parseParenAndDistinguishExpression (/home/lfdmr/Dev/test/web_frontend/node_modules/lingui-cli/node_modules/babylon/lib/index.js:3828:26)
    at Parser.pp$3.parseExprAtom (/home/lfdmr/Dev/test/web_frontend/node_modules/lingui-cli/node_modules/babylon/lib/index.js:3709:19)
error Command failed with exit code 1.

Thanks

Config params are considered unkown

In the new [email protected] parameters sourceLocale and fallbackLocale (as per https://lingui.gitbooks.io/js/content/ref/cli.html) are considered "unknown":

$ npm install lingui-cli -g --silent
/usr/local/bin/lingui -> /usr/local/lib/node_modules/lingui-cli/dist/lingui.js
+ [email protected]
added 102 packages in 9.13s
$ lingui extract
Extracting messages from source files…
● Validation Warning:

  Unknown option "fallbackLocale" with value "cs" was found.
  This is probably a typing mistake. Fixing it will remove this message.

See https://l.lingui.io/ref-lingui-conf for a list of valid options
● Validation Warning:

  Unknown option "sourceLocale" with value "cs" was found.
  This is probably a typing mistake. Fixing it will remove this message.

See https://l.lingui.io/ref-lingui-conf for a list of valid options
Collecting all messages…
Writing message catalogues…
Messages extracted!

configuration:

  "lingui": {
    "fallbackLocale": "cs",
    "sourceLocale": "cs",
    "localeDir": "<rootDir>/locales",
    "srcPathDirs": [
      "<rootDir>/src"
    ],
    "srcPathIgnorePatterns": [
      "/node_modules/",
      "/helpers/"
    ]
  }

However it does not affect functionality.

The library make-plural has issues with CSP

The library make-plural uses a new Function construct, which violates the script-src CSP rule.

Please see: https://developer.chrome.com/extensions/contentSecurityPolicy#relaxing-eval

Evaluated JavaScript
The policy against eval() and its relatives like setTimeout(String), setInterval(String), and new Function(String) can be relaxed by adding 'unsafe-eval' to your policy:

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
However, we strongly recommend against doing this. These functions are notorious XSS attack vectors.

I've opened an issue upstream eemeli/make-plural#10

using a wrapper arround js-lingui

In order to remove dependency on the i18n package, I tried making a single-point-of-entry file for i18n.
Something along the lines of:

import {withI18n, Trans} from 'lingui-react'

export {
	Trans,
	withI18n
}

However, this resulted in two problems:

  1. lingui-cli didn't collect any massage (using lingui extract)
  2. I got a warning

lingui-react preset is probably missing in babel config...

although lingui-react is not missing in babel config file (without the wrapping file, the warning is gone).
Also, all strings were seen as empty in the application.

Is this unsupported? Am I doing it wrong?

.js files shipped in npm are not ES5

Hi, it seems to me that the .js files shipped in npm are not ES5, so it wont work with IE11 and older

$ npm install --save-dev lingui-i18n
$ cat node_modules/lingui-i18n/lib/compile.js | grep -Hn '{ language,'
(standard input):73:    return formattedMessage(context({ language, params, formatStyles }));

it should be { language:language, params:params ...
And I guess there is the same problem with lingui-react

Thanks

Cannot add country locale such as pt_BR

Hi, it's usual for some countries to have their own sub locale inside a language.

lingui-cli does appear to support this at the moment. Is it possible to add support?

Thanks again! And good job on the library!

Allow built-in components in render prop

Just a small nitpick.

It's possible to use React.Component to render translation: <Trans render={Component}>...</Trans>, but built-ins can be passed as elements only: <Trans render={<h1 />}>...</Trans>.

Proposal: <Trans render="h1">...</Trans>

It's like 4 chars difference, but nice to have 😸

babel-plugin-lingui-extract-messages doesn't work when targeting IE 11

If I add the browser ie 11 to my babel-preset-env config, then I get some errors if I try to build my application:

[info] Module build failed: TypeError: ...: Cannot read property 'reduce' of undefined
[info]     at collectMessage (...\node_modules\babel-plugin-lingui-extract-messages\lib\index.js:24:27)

I'm not sure if this has to do with js-lingui or if it's an issue from another component.

Translation with variable inside does not work in production without extracted & compiled texts

Firstly, this issue only appears in production (without development prop on provider) and only if this translation wasnt extracted & compiled (just running those commands, no translation).
Having this:

{i18n.t`narozen ${birthdate}`}
<Trans>narozen {birthdate}</Trans>

should render (and on localhost/dev renders):
narozen 8.8.1943
narozen 8.8.1943
but on productions shows:
narozen {birthdate}
narozen {birthdate}

Issue disappeared after just running extract & compile, however this shouldn't happen. I don't understand the innerworkings, but if it is not capable of rendering it correctly in production without compile, it should also fail on dev, so there is no bad surprise after deploy..

Documentation proofreading

Happy Hacktoberfest!

Working on your first Pull Request? You can learn how from this free series How to Contribute to an Open Source Project on GitHub

Problem

There's a new documentation. However, I'm not a native english speaker and the documentation really needs some external proofreading.

List of pages:

How-to

All documentation is in docs folder. It's build using Sphinx Document Generator and uses reStructuredText.

If you want to build documentation locally, you need to have Python installed.

  1. Install pipenv tool:
pip install pipenv
  1. Install project dependencies
pipenv install

After making any changes, simply run make html inside docs folder.

cd docs
make html

Support

Need a help? Ping me on gitter. I live in Europe/Prague UTC+2 timezone and most of the time I answer questions on gitter instantly.

React Native Support

I'll expand this with issues as I find them, some may be unique to my project, so please bare with me:

  1. When React Native's builder transforms the source files with Babel, it seems to fail when trying to transform the imported lingui-react module. The transform succeeds if I remove the lingui-react babel preset, and fails if I use it.

  2. The provided components default to using <span> which doesn't exist with React Native, if it's possible to detect the environment, it should use <Text> instead, and pass through the style prop rather than className.

Pure JS interface

React components are great because they care of updates after language/message changes. However, sometimes it's necessary to get string directly instead of React node tree, e.g: for element attributes, document.title, etc. Sometimes it needs to be done even out of the ProvideI18n context, e.g. inside sagas (from redux-saga).

Phase 1 - Translation of raw ICU message format

const i18n = require('lingui-i18n')

// i18n.use(language: string, catalog: {[key: string]: string})
i18n.use('fr', {
    "Hello World": "Salut le Monde",
    "Hello, my name is {name}": "Salut, je m'appelle {name}"
})

// i18n.t(message: string, params: ?object): string
const translated = i18n.t('Hello world')
const withParams = i18n.t('Hello, my name is {name}', params={ name })

// i18n.compile(message: string): (params: ?object) -> string
const compiled = i18n.compile('Hello, my name is {name}')
compiled({ name })

This is the easiest use case. The only problem might be how to load messages into global object. Optionally add an API for precompiled messages.

This option isn't interesting at all, because many other libs already provides such functionality, but it's simple enough to keep it as a backup.

Implementation

  • i18n.use
  • i18n.t
  • i18n.compile

Phase 2 - ICU message format helper functions

Provide helper functions which mimic behavior of React components. Something like DSL for ICU message format:

const withParams = i18n.t`Hello, my name is ${name}`
const pluralize = i18n.plural({
    value: count,
    one: "# Book",
    other: "# Books"
})
const complex = i18n.select({
    value: gender,
    female: plural({
        value: numOfHosts,
        offset: 1,
        0: t`${host} does not give a party`,
        1: t`${host} invites ${guest} to her party`,
        2: t`${host} invites ${guest} and one other person to the party`,
        other: t`${host} invites ${guest} and # other people to his party`
    }),
    male: plural({...}),
    other: plural({...})
})

// "It happened {0, date, relative}"
const formats = i18n.t`It happened ${i18n.format.relative(value)}`
  • Does it require to use babel transformation to make it work? Or better question: What DSL doesn't require babel transformation? Yes
  • Does it makes writing messages easier than raw ICU message format? Type-checking, custom formats

Implementation

  • i18n.t
  • i18n.plural
  • i18n.select
  • Nesting
  • Custom formats

Force update PureComponent on language change

Having these two translations of the same word in a component

<input type="text" className="search__input" placeholder={i18n.t`Hledej`} />
<Trans>Hledej</Trans>

the placeholder is not updating correctly, while the usual <Trans> is. The component is updated upon language change, as well as the component with Provider. The placeholder is updated always on a second update (eg. a navigation), which causes it to be always in the wrong language when toggling languages (is delayed by 1 update). There is no problem with the <Trans> component.
Is there a way to resolve or bypass this problem (other than forcing update on didUpdate in every component...) ?
Thank you.

UPDATE:
Problem is resolved using Component instead of PureComponent, you are probably using context updates, which are ignored in PCs.

Avoiding "Localisation function not found for locale"

i18n.t requires activated language to match one of the CLDR language codes. If not, i18n.t will fail within messageformat.js, with an error message that is not so informative: "Localisation function not found for locale".

lingui can detect this when running the CLIlingui add-locale, and when i18n.activate is invoked.

React - Using <Trans> with object properties

I haven't had much luck doing

const component = (props) => {<Trans>Hello {props.user}</Trans>);

it always renders Hello undefined. However if I change it to

const component = ({user}) => (<Trans>Hello {user}</Trans>);

I get Hello Foo, which is the output I expected in the first case. Is this a bug that's easy to fix? I'll be happy to PR if you point me in the right direction.

HMR and change of active language

Trans component gets messages from context. Relying on an update of context is unsafe. I18nProvider should notify Trans components using listen/subscribe pattern.

Bonus: Figure out how HMR is working with message catalogues.

babel plugin tries to transform Select element from other than react-lingui library

Extract command crashed on one of my components (helper one, without any translations), had to remove it from parsing via ignore pattern. The reason it is crashing is completely strange to me.
The entire file (src\components\helpers\SearchableSelect.js):

import React, { PureComponent } from 'react'
import cls from '../../../styles/layout.less'
import InputLabel from 'material-ui/Input/InputLabel'
import FormControl from 'material-ui/Form/FormControl'
import FormHelperText from 'material-ui/Form/FormHelperText'
import Select from 'react-select'
import 'react-select/dist/react-select.css'

export default class SearchableSelect extends PureComponent {
  render() {
    const {name, value, options, label, helperText, changeHandler} = this.props
    let labelProps = {}
    if (value) {
      labelProps.shrink = true
    }
    return (
      <FormControl className={cls.formControl + ' ' + cls.selectField}>
        <InputLabel htmlFor={name} className={cls.inputLabel} {...labelProps}>{label}</InputLabel>
        <Select 
          className={cls.select}
          name={name}
          value={value}
          options={options}
          placeholder=''
          noResultsText={false}
          onChange={changeHandler}
        />
        {helperText && <FormHelperText className={cls.helperText}>{helperText}</FormHelperText>}
      </FormControl>
    )
  }
}

The error (@ lingui-cli\node_modules\babel-core\lib\transformation\file\index.js:590):

SyntaxError: ... /src/components/helpers/SearchableSelect.js: Missing fallback argument 'other'.
  17 |       <FormControl className={cls.formControl + ' ' + cls.selectField}>
  18 |         <InputLabel htmlFor={name} className={cls.inputLabel} {...labelProps}>{label}</InputLabel>
> 19 |         <Select
     |         ^
  20 |           className={cls.select}
  21 |           name={name}
  22 |           value={value}
    at File.buildCodeFrameError (lingui-cli\node_modules\babel-core\lib\transformation\file\index.js:427:15)
    at PluginPass.buildCodeFrameError (lingui-cli\node_modules\babel-core\lib\transformation\plugin-pass.js:64:53)
    at processElement (lingui-cli\node_modules\babel-plugin-lingui-transform-react\dist\index.js:186:20)
    at PluginPass.JSXElement (lingui-cli\node_modules\babel-plugin-lingui-transform-react\dist\index.js:396:21)
    at newFn (lingui-cli\node_modules\babel-traverse\lib\visitors.js:276:21)
    at NodePath._call (lingui-cli\node_modules\babel-traverse\lib\path\context.js:76:18)
    at NodePath.call (lingui-cli\node_modules\babel-traverse\lib\path\context.js:48:17)
    at NodePath.visit (lingui-cli\node_modules\babel-traverse\lib\path\context.js:105:12)
    at TraversalContext.visitQueue (lingui-cli\node_modules\babel-traverse\lib\context.js:150:16)
    at TraversalContext.visitMultiple (lingui-cli\node_modules\babel-traverse\lib\context.js:103:17)
    at TraversalContext.visit (lingui-cli\node_modules\babel-traverse\lib\context.js:190:19)
    at Function.traverse.node (lingui-cli\node_modules\babel-traverse\lib\index.js:114:17)

Create new, structured documentation

⚠️ Work in progress

Documentation

Website

  • New homepage (based on https://date-fns.org/)
  • Quick search bar
  • Auto build after commit to master
  • Make available package changelogs after release

Content

Tutorials

  • Javascript
  • React
  • CLI
  • Testing

References

  • lingui-i18n - i18n for Javascript projects
  • lingui-react - React components build on top of lingui-i18n (resolved in #22)
  • lingui-cli and lingui-conf
  • lingui-loader
  • ICU MessageFormat

Guides

  • Migrating from 0.x to 1.x
  • Working with pure components (update, withHash props)

Discussions

  • Performance
  • Writing ICU MessageFormat by hand vs. babel-preset-lingui preprocessors
  • Custom ID vs. default message for Message IDs (related #15)

"Trans is not defined" error when using only Plural

Lingui fires "Uncaught (in promise) ReferenceError: Trans is not defined" in a component that doesnt use Trans, only Plural (it is likely transformed?). But when I supply Trans, my linter is on fire (its not used) ...
I have to stick with:

import { withI18n, Trans, Plural } from 'lingui-react' // eslint-disable-line no-unused-vars 

in every component...

lingui-react 1.1.0
anyway, great job on the repo!

Cannot import default instance of I18n

The documentation states :

lingui-i18n still exports the default instance of I18n class, this remains unchanged:
import i18n from 'lingui-i18n'

But if I try to import it in my tests I get the warning:

"export 'default' (imported as 'i18n') was not found in 'lingui-i18n'

Same if I try to import the instance in the application itself.

Importing setupI18n works as expected.

import { setupI18n } from 'lingui-i18n';

const i18n = setupI18n();

Feature request: Allow no-op/lazy translations

Followup from #53

Sometimes it's necessary to mark strings which will be translated in the future, but leave them intact for now:

import { Trans, noop } from 'lingui-react'

const menu = [
  { to: '/about', title: noop('About') },
  { to: '/contact', title: noop('Contact') },
]

// later in the code
const Menu = () => 
  <div>{
    menu.map(item => 
      <Link to={item.to}>
        <Trans id={item.title} />
      </Link>)
  }</div>

Translation services accepting ICU?

hi! I understand that I can get the catalog from lingui and send that to translation, as outlined here, however, not many translation services work with ICU message format. Can somebody point me to tools that work on Mac and are able to convert ICU to XLIFF, which is the translation industry standard?

Can somebody point me to translation services that accept (ie. are able to translate) ICU?

the ICU website mentions genrb but I'm not sure it's available on mac.

also see formatjs/intl-messageformat#106

thanks!

Extract fails when files do not have import from 'lingui-react'

Hi, i'm setting up lingui on my project, but i wont need i18n for all files, but i get the following errors when using extract on the project:
image

Individual files that import {Trans} work fine. Is there any way to just ignore files without import and keep extracting others?

Thanks.

Convert ICU message to React element tree

Parse ICU message as a string and return a tree of React elements. This transformation allows using custom Format elements #6 and also speeds up rendering of messages with inline components.

messages.json is looking different than in documentation

Following https://lingui.gitbooks.io/js/tutorials/react.html got me to:

Now we're ready to extract messages:
$ lingui extract

And then it shows nicely formatted language file:

{
  "Message Inbox": "",
  "See all <0>unread messages</0> or <1>mark them</1> as read.": "",
  "{messagesCount, plural, one {There's {messagesCount} message in your inbox.} other {There're {messagesCount} messages in your inbox.}}": "",
  "Last login on {lastLogin, date}": ""
}

However mine looks very different, containing origin values (it does compile though):

{
  "StringOne": {
    "translation": "",
    "origin": [
      [
        "src\\components\\common\\Header.js",
        26
      ]
    ]
  },
  "StringTwo": {
    "translation": "",
    "origin": [
      [
        "src\\components\\common\\Header.js",
        53
      ]
    ]
  }
}

What am I doing wrong? I was just following the tutorial.

Neutrino: Template literals do not work when targeting IE 11

If I target the browser ie 11 in my babel-preset-env config, then the translation which are based on template literals do not work. I think it's because babel-preset-env pulls in transform-es2015-template-literals. It generates then code like this:

var _templateObject = _taggedTemplateLiteral(['This field is required'], ['This field is required']),
    _templateObject2 = _taggedTemplateLiteral(['Valid email required'], ['Valid email required']);

var defaultMessages = exports.defaultMessages = function defaultMessages(i18n) {
  return {
    isRequired: i18n.t(_templateObject),
    isEmail: i18n.t(_templateObject2)
  };
};

Without the transform-es2015-template-literals plugin, it creates code like:

const defaultMessages = i18n => ({
  isRequired: i18n._('This field is required'),
  isEmail: i18n._('Valid email required')
});

If I'm right then you transform also template literals t function calls, but now the transform-es2015-template-literals comes first and your transformation cannot be processed.

lingui doesn't work in Node.js

Hey,

if I try to use lingui in a SSR environment and I'll get an exception, because lingui-formats directly accesses the window-object, which doesn't exist in a node-environment.

Trace:

ReferenceError: window is not defined
at Object. (/Users/bb/Development/xxx/src/node_modules/lingui-formats/dist/index.js:5:24)
at Module._compile (module.js:573:30)
at Module._extensions..js (module.js:584:10)
at Object.require.extensions.(anonymous function) [as .js] (/Users/bb/Development/xxxx/src/node_modules/babel-register/lib/node.js:152:7)

Is SSR simply not supported at the moment, is it a bug or am I missing something?

Plural prop "zero" does not work as expected

Given

const resultCount = 0

This component:

<Plural
    value={resultCount}
    zero={`Nenalezen žádný koncert`}
    one={`Nalezen jeden koncert`}
    few={`Nalezeny ${resultCount} koncerty`}
    other={`Nalezeno ${resultCount} koncertů`}
/>

renders Nalezeno 0 koncertů

While this component:

<Plural
    value={resultCount}
    _0={`Nenalezen žádný koncert`}
    one={`Nalezen jeden koncert`}
    few={`Nalezeny ${resultCount} koncerty`}
    other={`Nalezeno ${resultCount} koncertů`}
/>

renders Nenalezen žádný koncert

Tested only in dev environment, lingui-react 1.1.0.

  • followup slightly related question:
    How to get React elements into plural?
    eg. Nalezeno <span className={cls.highlight}>{resultCount}</span> koncertů

lingui cli add-locale

Hi,
I just upgraded to the new version 1.0.0 of lingui, and I am encountering a problem with the command
lingui add-locale en
I got this messages if I don't create my locale path

yarn lingui v0.27.5
$ "/home/lfdmr/Dev/project/web_frontend/node_modules/.bin/lingui" "add-locale" "en"
fs.js:923
  return binding.mkdir(pathModule._makeLong(path),
                 ^

Error: ENOENT: no such file or directory, mkdir 'src/locales/en'

And when I create the path I got:

yarn lingui v0.27.5
$ "/home/lfdmr/Dev/project/web_frontend/node_modules/.bin/lingui" "add-locale" "en"
fs.js:923
  return binding.mkdir(pathModule._makeLong(path),
                 ^

>Error: EEXIST: file already exists, mkdir 'src/locales'`

Here is my config:

│ ├── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
├─┬ [email protected]
├─┬ [email protected]
│ └── [email protected]
├── [email protected]

Why React components instead of key or functions

Just to make it clear, there're two i18n APIs:

  • lingui-i18n, for vanilla javascript (i18n.t'Hello World'). This works without React and it's a base for future integrations.
  • lingui-react, for React components (<Trans>Hello World</Trans>) which under the hood uses lingui-i18n, so it's possible to use it for translation of attributes (<Trans title={i18n.t'Title'}>Hello World</Trans>)

Components vs. functions

React is all about rendering data. When data changes, React renders updates. Given example below:

<span>{i18n.t`Hello World`}</span>
<Trans>Hello World</Trans>

when language or message catalog changes, the span (or probably parent component) is responsible for update, while Trans take care of it itself. When parent component is optimized using shouldComponentUpdate, the Trans component will update the translated message even when parent skips update.

Reason 1: Using Trans component shifts responsibility from parent to Trans component itself. As a developer, you don't have to worry about skipped updates.

Second reason are inline components. Using Trans component you can go wild a do things like this:

<Trans>
   Any component is <strong className="green">valid</strong> here, even <Link>custom</Link> ones.
</Trans>

Example above will result in single entry in your message catalog: Any component is <0>valid</0> here, even <1>custom</1> ones.

This has several advantages:

  1. Translator doesn't care about html tags
  2. Props of inline components doesn't affect message
  3. You get only one message. This is obvious, but other libs (i18next, formatjs) translate content of inline components separately which is unfortunate for translators.

Reason 2: First-class support for inline components. As a developer, you can use JSX as you're used to. As a translator, you see the full message.

In future I'm planning further optimization, when message is rendered to React components tree and when props changes (like values, params) the message isn't parsed from scratch, but React handle update itself. Right now, message itself is cached, but inline components are rendered on each update.

Key vs. source language

// key
i18n.t`component.title`

// message in source language
i18n.t`Title`

Both approaches have pros & cons. I never settled to either solution. I'm trying to support both approaches:

// Key
<Trans id=`msg.hello`>Hello World</Trans>
// becomes {'msg.hello': 'Hello World'} for English

// Message
<Trans>Hello World</Trans>
// becomes {'Hello World': 'Hello World'} for English

I'm using second approach in examples because it's easier to start with.

Warn about missing `babel-plugin-lingui-react`

lingui-react/Trans renders empty components when babel plugin isn't installed.

    // constructor of Trans
    const translation = _this.getTranslation(props);

    // something like this for NODE_ENV == development
    // When babel-plugin is installed, props.children will be empty
    if (!translation && props.children) {
      console.warn('Missing babel-plugin')
    }

Why to use WithI18n instead of i18n object directly

Hi,
I encounter a problem when I use WithI18n, I got the following messages:

./src/App1/routes/Home/components/HomeView.js
Module build failed: SyntaxError: Unexpected token, expected ; (6:45)

  4 | import './HomeView.scss'
  5 | 
> 6 | export const HomeView = WithI18n()({ i18n }) => {
    |                                              ^
  7 |   return (
  8 |     <div>
  9 |       <h3><Trans>Welcome App 1!</Trans></h3>

 @ ./src/App1/routes/Home/index.js 1:0-45
 @ ./src/App1/routes/index.js
 @ ./src/App1/main.js

The code is

import React from 'react'
import { WithI18n, Trans } from 'lingui-react'

export const HomeView = WithI18n()({ i18n }) => {
  return (
    <div>
      <h3><Trans>Welcome App 1!</Trans></h3>
      <img
           src="/static/logos/logo_client.png"
           alt={i18n.t`Logo client`}
           />
    </div>
  )
}

export default HomeView

My configuration is:

├─┬ [email protected]
│ ├── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
├─┬ [email protected]
│ └── [email protected]
├── [email protected]

And I use Redux with this starter kit

So I tried import i18n from 'lingui-i18n' and everything works.

So why one should use WithI18n ?

Translations with variables stopped working on production after update

I had a similar issue earlier, but now I have tried everything, with zero results :/
After updating lingui-react to 1.1.1 and updating babel plugin to the latest version, some of my translation stopped working (in production -> dev = undefined). Only those, which have a variable or component inside and are untranslated, eg.

"Výsledky hledání pro <0>{searchedString}</0>": {
    "translation": "",
    "origin": [
      [
        "src\\components\\pages\\SearchResults.js",
        34
      ]
    ]
  }

SearchResults.js:

<Trans>
  Výsledky hledání pro <span className={cls.highlight}>{searchedString}</span>
</Trans>

It renders Výsledky hledání pro {searchedString}. I tried to extract & compile my catalog several times.. only thing that works, is adding a translation, which is impossible for me to do for every such translation for every language at this point of this project 😞 .
I hope it has a simple solution or I am doing something very wrong.

Catalog namespaces

I've been thinking about namespaces for a while and i18next/react-i18next#199 (comment) made me to write it down.

Multiple namespaces

Sometimes are messages split in several message catalogs. Both catalogs might contain message with the same ID and it that case it would be overwritten without namespacing messages from different catalogs.

This feature already exists in most i18n libs.

Local namespaces

What's more interesting and what I actually would like to do are local namespaces. There're two possible use cases:

  1. Reusable components
  2. Code splitting

Reusable components

Imagine you have a React component and you want to ship translations with it. Ideally, developer using this component should just spin up it's own i18n provider to activate language, but the messages should be loaded directly from component. All translations inside this components should be tied to the component only.

lingui-cli should only extract messages from 3rd party components if it isn't translated in some language, otherwise it should ignore it

Code spliting

As we split the code, we should be able to split the message catalog. This should be fully automated: only messages in bundled code are added to the bundle.

How to use unpackCatalog

Hi I have a problem with unpackCatalog

My catalog is

{
  "Welcome App 1!": {
    "translation": "Hi",
    "origin": [
      [
        "src/App1/routes/Home/components/HomeView.js",
        10
      ]
    ]
  },
  "Logo client": {
    "translation": "Best client",
    "origin": [
      [
        "src/App1/routes/Home/components/HomeView.js",
        14
      ]
    ]
  }
}

And when I use unpackCatalog(messages) I get:

{
    "languageData": {}
}

The key messages got undefined.

Cannot find flow definition for lingui-react

I try to use lingui-react with a project that uses flow. But I cannot get it working with flow, because flow cannot find the library definition.

Currently I get the error:

import { I18nProvider } from 'lingui-react';
                                  ^^^^^^^^^^^^^^ lingui-react. Required module not found

I've tried all the suggestions spread around in issue trackers or blocks. But none of them works. Flow typed does also not create stub definitions for the library. It's also not possible to include it as lib from the node_modules/lingui-react/lib/ directory, because the definitions are mixed with normal JS files which flow doesn't like.

Do you have any suggestion how the lib could be used with flow?

[Feature request] Check for missing messages and exit with error code if found

Hello,

My build pipeline is something like: lint > flow > test > build.
I would like to add checks for missing messages.

lingui extract produces a nice catalog statistics, that show if there are some missing translations.

Problem is, I can't plug it to my pipeline. I need a check that exits with error code, if there are some missing translations.
I'd like my pipeline to abort build and show error in this case.

Hopefully, this won't be hard to implement.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.