Search code examples
javascriptreactjstypescriptinternationalizationlinguijs

lingui library's macro t not working on react


I use the latest library for translation, but the macro t not working, the <Trans> working fine.

To Reproduce

  1. open codesandbox
  2. yarn install
  3. yarn start
  4. click different language on the top of screen

bug description:
only content in <Trans>content<Trans> will translated, but the last content on {hello react} not translated.

index.tsx:

import React from 'react';
import ReactDOM from 'react-dom/client';
import reportWebVitals from './reportWebVitals';
import { StoreProvider } from './components/store-provider';
import createStore from './store'
import { LanguageProvider } from './components/language-provider';
import { LangSwitcher } from './components/lang-switcher';
import { DataComponent } from './components/DataComponent';
import { Trans, t } from '@lingui/macro';

const store = createStore();

const root = ReactDOM.createRoot(
    document.getElementById('root') as HTMLElement
);
root.render(
    <React.StrictMode>
        <StoreProvider store={store}>
            <LanguageProvider>
                <LangSwitcher />
                <p>
                    <Trans>hello world</Trans>
                </p>
                <DataComponent data={t`hello react`} />
            </LanguageProvider>
        </StoreProvider>
    </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. 
reportWebVitals();

package.json:

{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@lingui/react": "^4.1.2",
    "@reduxjs/toolkit": "^1.9.5",
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^13.0.0",
    "@testing-library/user-event": "^13.2.1",
    "@types/jest": "^27.0.1",
    "@types/node": "^16.7.13",
    "@types/react": "^18.0.0",
    "@types/react-dom": "^18.0.0",
    "make-plural": "^7.3.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-redux": "^8.0.5",
    "react-scripts": "5.0.1",
    "redux-persist": "^6.0.0",
    "redux-saga": "^1.2.3",
    "typescript": "^4.4.2",
    "web-vitals": "^2.1.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
        "extract": "lingui extract --clean",
    "compile": "lingui compile --strict"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "@lingui/cli": "^4.1.2",
    "@lingui/macro": "^4.1.2"
  }
}

lingui.config.ts:

const linguiConfig = {
  catalogs: [
    {
      path: '<rootDir>/src/locales/{locale}/messages',
      include: ['<rootDir>/src'],
    },
  ],
  compileNamespace: 'cjs',
  fallbackLocales: {
    default: 'en-US',
  },
  format: 'po',
  formatOptions: {
    lineNumbers: false,
  },
  locales: [
    'en-US',
    'zh-CN',
    'zh-TW',
  ],
  orderBy: 'messageId',
  rootDir: '.',
  runtimeConfigModule: ['@lingui/core', 'i18n'],
  sourceLocale: 'en-US',
  pseudoLocale: 'pseudo',
}

export default linguiConfig

tsconfig.json:

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
        "baseUrl": "src"
  },
  "include": [
    "src"
  ]
}


Solution

  • Whenever you use the t macro in a React application, you should (1) "subscribe" your component to changes using the useLingui() hook, or (2) - use the defineMessage macro to define a message for later use. It has the same signature as t and returns a MessageDescriptor that you can pass to i18n._.

    I would suggest modifying your code as follows:

    index.tsx:

    import React from "react";
    import ReactDOM from "react-dom/client";
    import reportWebVitals from "./reportWebVitals";
    import { StoreProvider } from "./components/store-provider";
    import createStore from "./store";
    import { LanguageProvider } from "./components/language-provider";
    import { LangSwitcher } from "./components/lang-switcher";
    import { DataComponent } from "./components/DataComponent";
    import { Trans } from "@lingui/macro";
    import { msg } from "@lingui/macro";
    
    const store = createStore();
    
    const root = ReactDOM.createRoot(
      document.getElementById("root") as HTMLElement
    );
    root.render(
      <React.StrictMode>
        <StoreProvider store={store}>
          <LanguageProvider>
            <LangSwitcher />
            <p>
              <Trans>hello world</Trans>
            </p>
            <DataComponent data={msg`hello react`} />
          </LanguageProvider>
        </StoreProvider>
      </React.StrictMode>
    );
    
    reportWebVitals();
    

    DataComponent.tsx:

    import { MessageDescriptor } from "@lingui/core";
    import { useLingui } from "@lingui/react";
    
    type props = {
      data: MessageDescriptor;
    };
    
    export const DataComponent: React.FC<props> = ({ data }) => {
      const { i18n } = useLingui();
    
      return <p>{i18n._(data)}</p>;
    };
    

    Tested in the sandbox and it works as expected.