How to extract custom Lingui wrapper in React?

127 Views Asked by At

I created a custom Lingui wrapper in a React project:

function translate(translateObject: ITrenslatable) {
  const { i18n, id, fallback, values, comment } = translateObject;

  let translatedText = i18n._({
    id,
    message: fallback,
    values,
    comment,
  });

  if (translatedText == id) {
    translatedText = i18n._({
      id: Math.random().toString(),
      message: fallback,
      values,
      comment,
    });
  }

  return translatedText;
}

In the future, this custom wrapper may how additional features, and I'm also planning on making a <Translate /> tag that uses the function above under the hood to achieve custom translating behavior.

Edit: currently I need this function because:

  1. I want to create a layer of abstraction between my application and translation.
  2. I need this wrapper function to be able to provide a default value, because otherwise if there were missing translations (e.g. translation only available in English, and not Hungarian, only the id would be displayed when switched to Hungarian).

The custom function works exactly as expected when used on already extracted text, but unfortunately, I cannot extract from this function.

It looks like this when used:

translate({
      i18n,
      fallback: "User at {id}",
      id: "user.title",
      values: { id: props.id },
})

How do I make Lingui find and extract my custom translate function?

Thank you for reading!

2

There are 2 best solutions below

0
Steffen Frank On

I have not used Lingui myself and did no try out this solution, but according to the documentation, what you should probably do is:

Create a custom extractor that parses your code and inserts /*i18n*/ annotations to the calls of your translate function, so the parameters passed to this function can then be picked up by the default extractor:

import { extractor as defaultExtractor } from "@lingui/cli/api";

export const extractor: ExtractorType = {
  match(filename: string) {
    return defaultExtractor.match(filename);
  },
  extract(filename: string, code: string, onMessageExtracted, ctx: ExtractorCtx) {
    const annotatedCode = code.replace(/\btranslate\s*\(/, "translate( /*i18n*/ "
    return defaultExtractor.extract(filename, annotatedCode, onMessageExtracted, ctx);
  },
};

...and add your extractor to the lingui.config.ts file:

import { extractor } from './my-custom-extractor.ts'
module.exports = {
  [...]
  extractors: [extractor]
}

Please be aware that this is prone to some errors, e.g. if somebody choses to define an alias for the translate function like this, the extraction will not work:

import {translate as t} from "your-package";
0
vonovak On

You can customize how the lingui cli extracts strings, as documented here https://lingui.dev/ref/conf#runtimeconfigmodule

I understand that you want to have an abstraction layer, but looking at your example, I don't think what you're doing is a good idea, and I'd rather follow the approach recommended by the official docs.

Also, if your if (translatedText == id) condition is meant to detect untranslated strings, it's wrong - it will work only for simple use cases but not for plurals and other more complicated stuff.

To provide fallbacks, look at https://lingui.dev/ref/conf#fallbacklocales

Hope this helps! :)