Code Monkey home page Code Monkey logo

i18next-icu's Introduction

i18next: learn once - translate everywhere Tweet

CI Code Climate Coveralls Package Quality cdnjs version npm version npm

i18next is a very popular internationalization framework for browser or any other javascript environment (eg. Node.js, Deno).

ecosystem

i18next provides:

For more information visit the website:

Our focus is providing the core to building a booming ecosystem. Independent of the building blocks you choose, be it react, angular or even good old jquery proper translation capabilities are just one step away.

Documentation

The general i18next documentation is published on www.i18next.com and PR changes can be supplied here.

The react specific documentation is published on react.i18next.com and PR changes can be supplied here.


Gold Sponsors


From the creators of i18next: localization as a service - locize.com

A translation management system built around the i18next ecosystem - locize.com.

locize

With using locize you directly support the future of i18next.


i18next-icu's People

Contributors

adrai avatar cellog avatar dependabot[bot] avatar henrinormak avatar jamuhl avatar jesseyay avatar karoun avatar offirgolan avatar sidoruk-sv avatar vovan-ve 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

Watchers

 avatar  avatar  avatar  avatar

i18next-icu's Issues

How to handle different timezones in nodejs

Hi, I am trying to use this module in nodejs to send emails to different customers. Each customer can have a different language and/or timezone. Do you have any examples on how to set the timezone per call? All i have now is this

function getText(lang) {
  return i18next.t('This is an example of date formatting: {value, date, short}', {lang: lang, value: new Date()});
}

i18next used in index.d.ts but missing in dependency

๐Ÿ› Bug Report

When using pnpm in project, ICU instance's type will be imcompatible with i18next.use

To Reproduce

use pnpm to install dependencies.

import i18next from 'i18next';
import ICU from 'i18next-icu';

const icu = new ICU();

// ts error on blow 'icu'
i18next.use(icu).init();

Type 'IcuInstance<IcuConfig>' provides no match for the signature 'new (...args: any[]): Module'.ts(2345)

as pnpm will not hoist all dependencies to root's node_modules. i18next-icu will not have access to i18next unless dependency was declared in package.json.

Possible solution

add i18next as dependency in package.json

link to pnpm issue pnpm/pnpm#3788

IntlMessageFormat and custom formatters

Hi @jamuhl ๐Ÿ‘‹

I'm opening this issue to discuss how custom formatters could be added to i18next-icu. It seems that MessageFormat you are leveraging has this functionality already, it's jut not exposed into the API of i18next-icu. See the docs here:

https://messageformat.github.io/messageformat/page-guide#toc11__anchor
https://messageformat.github.io/messageformat/MessageFormat.html#addFormatters

The reason why I have started exploring custom formatters is because I would like to output values with certain numbers of fractional digits, e.g. 1, 3 or 6.

Here's how my translation files could look in an ideal world:

{
  "example1": "Our value is equal to {value, numberWithThreeFractionalDigits}.",
  "example2": "Our value is roughly equal to {value, numberWithFD, 1}, but if you like things to be precise, it is {value, numberWithFD, 6}.",
}

I'm not yet sure what I'd write in addFormatters() to define numberWithThreeFractionalDigits, numberWithFD or whatever. But before I get there, it'd be great to know how addFormatters() could be called from i18next-icu. I see you are doing something smart about memorisation of IntlMessageFormat here, which needs to be taken into account:

i18next.IntlMessageFormat = IntlMessageFormat;

i18next-icu/src/index.js

Lines 45 to 53 in 133d297

let fc;
if (this.options.memoize) {
fc = utils.getPath(this.mem, `${lng}.${ns}.${key}`);
}
if (!fc) {
fc = new IntlMessageFormat(res, lng);
if (this.options.memoize && (this.options.memoizeFallback || !info || hadSuccessfulLookup)) utils.setPath(this.mem, `${lng}.${ns}.${key}`, fc);
}
return fc.format(options);

Being able to define custom formatters in the ICU plugin will make it as extensible as the main formatter. And in turn this will add even more value to the synergy i18next ecosystem creates!

Map i18next language code to ICU locale

๐Ÿš€ Feature Proposal

I propose adding a way of mapping from the i18next language code to another code.

Motivation

There may be a case where multiple sets of translations are required for the same language. For example, if a web app is deployed to multiple companies, each company may need their own company-specific set of translations, even though they're still using the same underlying language and locale.

At the moment I'm partially getting around this by using multiple custom region suffices, with the appropriate language code. e.g. en-ab, en-en, en-xy. This ensures that the correct plural forms are used. Unfortunately it ends up causing the wrong date formats to use, as they are based on the second part of the code.

It would be useful to be able to have resource packs named with arbitrary names, e.g. bobswidgets, sparklythings, default, and then be able to have a function which maps those names to correct locales. Or perhaps to use the modified codes as before (en-ab, en-en, en-xy) and map them to real locales (en-gb).

Although I particularly need this for i18next-icu, it may actually make sense to implement it in the main i18next package.

Unable to add custom format.

I'm looking for the possibility to add default values to interpolation.
For example, I have this key: 'Hello {user}'
And user in my case is optional.
So what I want to add defaultValue formatter.
And my key should look like 'Hello {user, devaultValue, a user}'
And I didn't find out a way to add such formatter.

date formatting with ICU

Hi,
I've started using i18next with ICU and it works great with plurals. So first of thanks for this library!

One problem I encountered is that when I try to use date formatting via {x, date, short}, I currently only get some formatting into what mostly looks like ISO, but in some cases like Latvian for example, I'm getting result "2022 M11 14", when really what was expected is "14.11.2022".

The project is using node 8.10.0, Typescript (and yarn 1.21.1).
(Pushing to update node version is not possible)

I see that when you don't use ICU, you have formatting options as part of init via interpolation, but the syntax is completely different from ICU, using double {{}} and providing the format itself. Is there something similar we could use for ICU?

What I need is the user friendly short version for each translation, as mentioned above ๐Ÿ‘†.
Best case would be if translators would not have to provide formatting of date.

Thanks!

skipInterpolation option is not being respected

When using this plugin and trying to do t('stringId', { skipInterpolation: true } you simply get and error message "The intl string context variable 'abc' was not provided to the string...".

Define an actual interface for IntLocaleData

The IntLocaleData TS interface looks like this:
interface IntlLocaleData {}

My suggestion is to define an actual interface for this.
Otherwise, when trying to grab a property of a specific locale object, every property I'll try to get, will hit a Property '...' does not exist on type 'LocaleData'

Otherwise, there is no way to work with the default export of the locale data with TS

Is there a way to not fail on invalid translations, but fallback in non-breakable maner

For keys, where some invalid key or non-passed variable is used, all the application is broken with an unhandled exception.

For example:

  1. key with minus for unescape, that is valid for i18next without ICU, but will fail your production when using with ICU plugin:

Example key:

{
  "test_unascaped_variable__key": "some {- key}"
}

Runtime exception:

  SyntaxError: Expected "," or "}" but "k" found.

      at peg$buildException (../../../../../src/parser.js:363:14)
      at Function.peg$parse (../../../../../src/parser.js:1382:13)
      at new MessageFormat (../../../../../src/core.js:21:27)
      at ICU.parse (node_modules/i18next-icu/dist/commonjs/index.js:120:14)
      at Translator.extendTranslation (node_modules/i18next/dist/cjs/i18next.js:708:31)
      at Translator.translate (node_modules/i18next/dist/cjs/i18next.js:692:20)
      at I18n.t (node_modules/i18next/dist/cjs/i18next.js:2139:80)
      at fixedT (node_modules/i18next/dist/cjs/i18next.js:2122:23)
      at TestComponentInvalidKey (src/TranslateProvider/TranslateProvider.driver.tsx:65:48)
  1. non-passed variable also works great (is ignoring) with i18next
{
	"test_empty_variable": "some absent here {variable}"
}

but also causing the runtime exception

The intl string context variable 'variable' was not provided to the string 'some absent here {variable}'

      at MessageFormat.format (../../../../../src/core.js:48:17)
      at ICU.parse (node_modules/i18next-icu/dist/commonjs/index.js:124:17)
      at Translator.extendTranslation (node_modules/i18next/dist/cjs/i18next.js:708:31)
      at Translator.translate (node_modules/i18next/dist/cjs/i18next.js:692:20)
      at I18n.t (node_modules/i18next/dist/cjs/i18next.js:2139:80)
      at fixedT (node_modules/i18next/dist/cjs/i18next.js:2122:23)
      at TestComponentInvalidKey (src/TranslateProvider/TranslateProvider.driver.tsx:66:51)

It is OK to fix those errors one time to not getting exceptions on production when it is a small project.

But when the translation process is separated from development, it could be harmful that localization could break the whole application.

So as a fallback showing translated key, without interpolated invalid value (so showing in UI some absent here {variable}) is better, then failing with an exception. And showing React error boundaries errors for every place where translations are affected (could be in any key, any language).

Otherwise, we had to add some tests for checking translation files somehow (need to be invented), before using them.

Memoize lookup in parse is producing false positives

This issue relates to the use of memoization in this code: https://github.com/i18next/i18next-icu/blob/master/src/index.js#L47-L59

Namely, given two strings with the following keys, foo.bar.baz and foo.bar, if parse happens to run first for foo.bar.baz, the later lookup for foo.bar will produce a false positive (the check on line 54 is truthy, eventhough this particular key has not yet been memoized), which leads to an error at line 58 (fc.format is undefined and not a function).

Likely it would be enough to swap the simple truthy check with something a bit more accurate (such as !fc && typeof fc.format === 'fuction').

Until then, the only real workaround (without changing keys) is to disable memoization (which is an overhead). Please let me know if you need further details, I can file a PR if needed.

Upgrading to 2.0.2 - Failed to Compile - Module not found

Hello,

I was following this tutorial that help me set up i18next-icu on my react app.
https://medium.com/@danduan/translating-react-apps-using-i18next-d2f78bc87314

It was working fine, but when updating from 1.4.2 to 2.0.2 the following error started appearing:

./src/i18nextConf.js
Module not found: Can't resolve 'i18next-icu/locale-data/en' in '/home/valverde/dev/sabores-ecommerce/frontend/src'

Is there something that needs to be changed on the apps to upgrade to 2.0.2?

Thanks for the help

ReferenceError: module is not defined

๐Ÿ› Bug Report

Using i18next-icu in browser will result ReferenceError: module is not defined error.

To Reproduce

Install i18next and i18next-icu and load in html file like below

npm install i18next i18next-icu

in the html file

<html>
<head>
  <script src="node_modules/i18next/i18next.min.js"></script>
  <script src="node_modules/i18next-icu/i18nextICU.js"></script>
</head>
<body>
  <script>
   i18next
    .use(i18nextICU)
    .init({
        lng: "en",
        resources: {
            en: {
            translation: {
                key:
                "You have {numPhotos, plural, " +
                "=0 {no photos.}" +
                "=1 {one photo.}" +
                "other {# photos.}}"
            }
            }
        }
    });
    i18next.t("key", { numPhotos: 1000 })
  </script>
</body>
</html>

Expected behavior

Javascript above run successfully, instead of returning Uncaught ReferenceError: module is not defined error.

Environment

  • runtime version: chrome browser 107.0.5304.121
  • i18next version: 22.0.6
  • i18next-icu version: 2.0.3
  • os: Mac

i18next-icu incompatible with react-i18next <Trans>

๐Ÿ› Bug Report

When using i18next-icu 2.0.0 with a react-i18next <Trans> component, the parsing fails, and no arguments are replaced.

This is because IntlMessageFormat 2.x did not have the ignoreTag option. Version 9.4.6 now has this, which means that when IntlMessageFormat sees a placeholder like <0></0> it expects that to exist in the options, much like the value in the reproduce case below. react-i18next and other implementations handle the placeholders above the icu parser, and so the ignoreTag option should be enabled.

To Reproduce

// Paste your code here
import { Trans } from "react-i18next/icu.macro";

function ComponentThatUsesTrans () {
  const value = "this is not replaced";
  return (
    <Trans i18nKey="some-key">
      This <b>bold tag</b> triggers an error, and as a result
      {value} is not replaced
    </Trans>
  );
}

Expected behavior

The translation should be "This <b>bold tag</b> triggers an error, and as a result this is not replaced"
but is "This <b>bold tag</b> triggers an error, and as a a result {value}"

Your Environment

  • runtime version: i.e. node v14, deno, browser xy
  • i18next version: i.e. 19.5.3
  • os: Mac, Windows, Linux
  • any other relevant information

intl-messageformat is egregiously out of date

๐Ÿ› Bug Report

The current version of intl-messageformat is 9.4.6, and this package depends on 2.2.0. This breaks all of the date skeleton formats described in https://formatjs.io/docs/intl-messageformat#datetime-skeleton

Would you accept a PR bumping the intl-messageformat version in package.json?

To Reproduce

A codesandbox example or similar
or at least steps to reproduce the behavior:

t("month-label", "{ date, date, ::MMMMyyyy }", { date: new Date() });

Expected behavior

It should format with "February 2021" but instead formats as "02/08/2021"

Your Environment

  • runtime version: n/a
  • i18next version: 19.8.4
  • os: Mac
  • any other relevant information

addLocaleData functionality is removed in 2.0 and no migration docs are provided

Previous version 1.4.X included instructions on how to add a language at runtime.

import i18next from 'i18next';
import ICU from 'i18next-icu';
import fr from 'i18next-icu/locale-data/fr';

const icu = new ICU();
icu.addLocaleData(fr);

This methodology is completely removed from the 2 release and I cannot find any instructions or migration documentation.

Can someone please provide some guidance on why this was removed, what its impact is and how to mitigate it on upgrade? Links to other documentation would be fantastic. Happy to make a PR to update docs here to help other folks out.

No TypeScript support

Hello!

Please, add TypeScript support.

Currently I just started with this package and documentation, and at the moment I have to add following minimal declarations to let app to work:

declare module 'i18next-icu' {
  import { ThirdPartyModule } from 'i18next';

  export interface LocaleData {}

  export interface IcuConfig {
    localeData: LocaleData | LocaleData[];
  }

  export interface IcuInstance extends ThirdPartyModule {}

  interface IcuConstructor {
    new (config?: IcuConfig): IcuInstance;
  }

  const ICU: IcuConstructor;
  export default ICU;
}

declare module 'i18next-icu/locale-data' {
  import { LocaleData } from 'i18next-icu';

  declare const localesData: LocaleData[];
  export default localesData;
}

declare module 'i18next-icu/locale-data/en' {
  import { LocaleData } from 'i18next-icu';
  declare const localeData: LocaleData;
  export default localeData;
}

Currency Message Format not working.

๐Ÿ› Bug Report

I am using react-i18next with i18next-icu to support Intl Message formatting. It works as defined here https://formatjs.io/docs/intl-messageformat for Date, Time, Number and Plurals but does not work for currency. I tested this with Intl-messageformat alone and the currency formatting works fine, but doesn't work with i18next-icu.

i18next-icu uses intl-message version 2.2.0 but the latest version available is 9.3.20. The issue is still there with the latest version as well.

To Reproduce

Here is the codesandbox link to reproduce the issue. The error case is shown is red and the expected behaviour in green.

Expected behavior

I expect the string {price, number, ::currency/CAD}" to be formatted through Intl Message format as currency but it is formatting this as a number.

Your Environment

  • runtime version: i.e. node v12.19.0
  • i18next version: i.e. 19.8.4
  • os: Mac

ICU Interpolation does not work with React Native production bundle

๐Ÿ› Bug Report

We are running a React Native app for Windows using Hermes bytecode optimization to generate our JavaScript bundle. When trying to use the ICU format for i18next, everything seems to work fine when loading our JavaScript bundle ad-hoc via metro in our usual development flow. However, when we use a production bundle interpolation ceases to work.

To Reproduce

We do have a Suspense element wrapped around the component we are trying to render with the useTranslation hook. Everything works fine if we stop using the ICU format in the i18n object and change the interpolation prefix/suffix to single curly-braces.

import { initReactI18next } from 'react-i18next';
import Backend, { HttpBackendOptions, RequestCallback } from 'i18next-http-backend';
import { IErrorResponse, NativeDataHandler } from './common/dataHandler/NativeDataHandler';
import i18n, { InitOptions, ResourceKey } from 'i18next';

// Create wrapper for React Native Module APIs
const dataHandler = new NativeDataHandler();

i18n
  .use(ICU)
  .use(Backend)
  .use(initReactI18next)
  .init({
    // There is no need to define the language or fallback language here, as we use native code in a Route Handler
    // to read the system language and return the correct translation file.
    interpolation: {
      escapeValue: false // React is already safe from XSS attacks, so no need to escape.
    },
    react: {
      useSuspense: true
    },
    debug: false,
    initImmediate: false, // Avoid initializing immediately, since we defer to the native backend request to load translations.
    backend: {
      request: async (
        backendOptions: HttpBackendOptions,
        loadPath: string,
        payload: {} | string,
        callback: RequestCallback
      ): Promise<void> => {
        // Make a call through the NativeDataHandler to retrieve the correct translations file based on device locale.
        // Note that although we do not call an actual HTTP endpoint, the translations are retrieved in a similar async fashion.
        const response: ResourceKey = await dataHandler.getTranslations();
        if ((response as IErrorResponse).error) {
          callback(null, {
            status: 500,
            data: response
          });
        } else {
          callback(null, {
            status: 200,
            data: response
          });
        }
      }
    }
  } as InitOptions);

export default i18n;

Expected behavior

If we use a translation like this:
helloUser: "Hello {1}"

The following should work with production bundles as well as developer/debug mode via metro:

const t = useTranslation();
t('helloUser', {1: 'Frank'}); // Should display "Hello Frank", instead displays "Hello {1}"

Your Environment

  • runtime version: node v18, react-native-windows, hermes
  • i18next version: 23.4.4
  • os: Windows
  • Hermes bytecode compiled bundle

Does the locale data files really have to be so big?

es.js is 13.4KB, en.js is 7.2KB but jp.js is only 1.13KB
Why is thereโ€™s so much difference? Do these files really have to have so many actual translations? Couldnโ€™t they just include the ICU rules and not the actual words?

Enabling ICU breaks interpolation

๐Ÿ› Bug Report

When ICU is enabled on i18next with react-i18next, some interpolations aren't executed. When .use(ICU) is commented out, the interpolation is working correctly.

To Reproduce

https://codesandbox.io/s/icu-interpolation-ix0cl3

Expected behavior

The text "User test has been created" is shown on the page.

Actual behavior

The text "User {{ what }} has been created" is shown on the page. Notice that the interpolation is not executed.

Your Environment

  • runtime version: Google Chrome 107.0.5304.107 and Mozilla Firefox 107.0
  • i18next version: i.e. 22.0.6
  • i18next-icu version: 2.0.3
  • react-i18next version: 12.0.0
  • react version: 18.2.0
  • intl-messageformat version: 9.13.0
  • os: Windows 11 22H2 (22621.819)

Fallback strings are not formatted using the target locale.

๐Ÿ› Bug Report

Any translations that uses fallback strings will also use the fallback locale to format them instead of the target locale.
Using {{date, datetime}} without i18next-icu the fallback would still use the target locale to format the date.

To Reproduce

Fallback to en

import i18next from "i18next";
import ICU from "i18next-icu";

i18next.use(ICU).init({
  lng: "fr-CA",
  resources: {
    en: {
      translations: {
        short_date: "{date, date, short}"
      }
    }
  }
});

i18next.t("short_date", { date: new Date(2000, 1, 29) }); // 2/29/00 (Which is the en-US way to write it.)

Fallback to fr

import i18next from "i18next";
import ICU from "i18next-icu";

i18next.use(ICU).init({
  lng: "fr-CA",
  resources: {
    en: {
      translations: {
        short_date: "{date, date, short}"
      }
    },
    fr: {
      translations: {
        short_date: "{date, date, short}"
      }
    }
  }
});

i18next.t("short_date", { date: new Date(2000, 1, 29) }); // 29/02/00 (Which is the fr-FR way to write it.)

Expected behavior

import i18next from "i18next";
import ICU from "i18next-icu";

i18next.use(ICU).init({
  lng: "fr-CA",
  resources: {
    en: {
      translations: {
        short_date: "{date, date, short}"
      }
    }
  }
});

i18next.t("short_date", { date: new Date(2000, 1, 29) }); // 00-02-29 (Which is the fr-CA way to write it.)

Your Environment

  • runtime version: node v18.17.0, npm 9.6.7, deno, browser Chrome/116.0.0.0
  • i18next version: 23.4.5
  • os: Windows 10 (WSL Ubuntu 20.04)

memoize saves fallback with async backend

In our app, we use key-based fallback with an asynchronous i18next backend with react-i18next and i18next-icu.

When using react-icu with the default settings, it looks like memoization incorrectly memoizes the fallback keys, even after the translations have been loaded.

I can fix this right now by calling ICU.mem = {} manually after a new translation has been loaded. This should probably not happen in the first place though.

Alternatively, you might want to expose a (documented) method to clear the memoization cache.

Currency in skeleton with unit-width-iso-code does not work.

๐Ÿ› Bug Report

I'm trying to translate a string by passing in a numeric value, (auctionFee), but the skeleton implementation does not seem to return the correct formatting. It returns kr
{auctionFee, number, ::currency/SEK unit-width-iso-code}

To Reproduce

"i18next": "^21.10.0",
"i18next-http-backend": "^1.4.1",
"i18next-icu": "^2.1.0",
"i18next-vue": "^2.0.0-beta.0",
"intl-messageformat": "^10.3.3",
 "js-yaml": "^4.1.0",
 "vue": "^3.2.31",
// Paste your code here
JS (vue):
this.$t('JS_TEXT_LABEL_BID-PAYMENT-INFO_AUCTION-FEE_EX-VAT', {auctionFee: this.productData.auctionFee})
JS_TEXT_LABEL_BID-PAYMENT-INFO_AUCTION-FEE_EX-VAT: >-
  {auctionFee, number, ::currency/SEK unit-width-iso-code}

Expected behavior

I expect the skeleton to return the value sent in with SEK appended after the auctionFee value. What i'm getting back is "kr", and this is not the iso code for the currency. If i were to change "unit-width-iso-code" to "unit-width-full-name" I would get "svenska kronor" which is correct.

So when I'm expecting the ISO code it does not work.

Your Environment

  • i18next version: 21.10.0
  • os: Mac

Interpolation not working in ICU format when fetching an endpoint

๐Ÿ› Bug Report

Hello everyone, we were trying to pass some data for this json:
{"delete_board_modal_title" : "Delete {title}"}

in this way :

  <Trans
    i18nKey="delete_board_modal_title"
    values={{ title: boardTitle }}
  />

//or like this

{t("delete_board_modal_title", { title: boardTitle })}

but it seems to not interpolate correctly the curly brace because I see this result Delete {title}.
The weirdest thing is that if we use a local folder public/locales/en_US.json is working correctly but not when is fetching from this endpoint: https://ourBeautifulEndpoint.com/v2/en_US.json.
Or it also works like this:
<Trans i18nKey="Delete {title}" values={{ title: boardTitle }} />
or it works with the double curly braces but it's not what we want because we need ICU format.
Maybe we are missing something important for sure, what should we do?

This is the I18next config:

import i18next from "i18next";
import HttpApi from "i18next-http-backend";
import LanguageDetector from "i18next-browser-languagedetector";
import ICU from "i18next-icu";
import { initReactI18next } from "react-i18next";

const backendOptions = {
  type: "backend",
  allowMultiLoading: true,
  loadPath: "https://ourBeautifulEndpoint.com/v2/{{lng}}.json"
};

i18next
  .use(ICU)
  .use(HttpApi)
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    backend: backendOptions,
    whitelist: ["en_US", "it_IT"],
    detection: {
      order: ["path", "cookie", "localStorage", "sessionStorage"],
      lookupQuerystring: "lng",
      lookupCookie: "i18next",
      lookupLocalStorage: "i18nextLng",
      lookupSessionStorage: "i18nextLng",
      caches: ["localStorage", "cookie"]
    },
    keySeparator: true,

    debug: true,

    react: {
      useSuspense: false,
      bindI18n: "languageChanged"
    }
  });

export default i18next;

Environment

  • runtime version: node v14.19.1
  • i18next version: {
    "i18next": "^21.8.9",
    "i18next-browser-languagedetector": "^6.1.4",
    "i18next-http-backend": "^1.4.1",
    "i18next-icu": "^2.0.3"
    }
  • os: Mac chip m1 macOs Monterey

Thanks in advice and sorry if this is not a bug or it is duplicated

local-data folder NOT in i18next-icu 2.0.3

Hello,
I am working on upgrading i18next-icu from 1.4.2 -> 2.0.3, however, seems locale-data folder does not seem exist anymore.
If that is the case, may I know how to access locale files?. Like in this documentation - https://www.npmjs.com/package/i18next-icu/v/1.4.2, can see import fr from 'i18next-icu/locale-data/fr'; exist but this does not apply for v2.0.3. May I know how can we access locale files in this case. I could not find any example or any link that might be helpful for this.
Best,
Priya

Help wanted: Pluralization for russian

Can't understand what I'm doing wrong, but pluralization doesn't work as expected.

It works, but only for one and other cases, as in English, despite the fact that Russian language has 4 plural forms.

ICU format is correct.

{count, number} {count, plural, one {one} few {few} many {many} other {other}}

Iterating through numbers from 1 to 200 I'm getting the next results:

1 one
2 other
3 other
4 other
5 other
6 other
7 other
8 other
9 other
10 other
11 other
12 other
13 other
14 other
15 other
16 other
17 other
18 other
19 other
20 other
21 other
22 other
...

Definition of plural forms:
http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ru

Sandbox with example: https://codesandbox.io/s/lypy5z7pkz

Plural and number format combination

Hi, I have search through the google and github and no luck with a solution so I start an thread to ask.

Shop {numOfItems, plural, =1 {1 Item} other {# Items}}

My goal is to have number and plural formation together from a key:
English: Shop 10,000 Items
French: Shop 10 000 Items

But I am getting the following at the moment:
English: Shop 10,000 Items
French: Shop 10,000 Items

Is that possible? currently seems like I can only do either number or plural or currency separately.

"i18next": "^20.3.5",
"i18next-browser-languagedetector": "^6.1.3",
"i18next-chained-backend": "^4.2.0",
"i18next-http-backend": "^2.2.1",
"i18next-icu": "^2.0.3",
"i18next-localstorage-backend": "^4.1.1",
"next-i18next": "^12.1.0",

If I try to localize the number myself, the final result becomes a string "10,000" and won't be able use the ICU plural format.

thanks!

Loading locale data at runtime

Hello, I was wondering how you suggest this is used when loading locale remotely at runtime. For example, if this is used with i18next XHR module, changing ones locale would require to do
icu.addLocaleData({newLocaleData}); somewhere.

Ideally I would not want to bundle all the locale data in my application bundle, thus I am looking at some guidance on how to achieve that.

Thanks!

Memoized cache should be busted when new resources are added

I ran into this issue when setting up react-i18next with gatsby when hot reloading the translations weren't working. This was a major troll not gonna lie lol.

i18next.addResourceBundle(locale, 'translation', { foo: 'bar' }, false, true);
i18next.t('foo') // => 'bar'
i18next.addResourceBundle(locale, 'translation', { foo: 'baz' }, false, true);
i18next.t('foo') // => 'bar'
"dependencies": {
    "i18next": "^19.3.2",
    "i18next-icu": "^1.2.1",
    "react-i18next": "^11.3.3"
  },

My current work around is to turn off memoize in the dev environment but I feel like this should be something handled by this library or provide a way to manually clear the cache.

ICU pluralisation in Android React Native app breaks if label has #

Which package?

"react-native": "0.61.2",
"i18next": "17.2.0",
"i18next-icu": "2.0.3",
"intl-messageformat": "9.4.6",

"@formatjs/intl-getcanonicallocales": "1.8.0",
"@formatjs/intl-locale": "2.4.41",
"@formatjs/intl-pluralrules": "4.2.0",

Describe the bug

When I use plural labels in my JSON and they include '#' following ICU format, these label are broken in my app without throwing any error.

To Reproduce

import i18n, { InitOptions } from 'i18next';
import ICU from 'i18next-icu';
import { initReactI18next } from 'react-i18next';
import '@formatjs/intl-getcanonicallocales/polyfill'
import '@formatjs/intl-locale/polyfill'
import '@formatjs/intl-pluralrules/polyfill'
import '@formatjs/intl-pluralrules/locale-data/en'

//On my app init
 i18n.use(languageDetector(cfg))
        .use(ICU)
        .use(initReactI18next)
        .init({
              fallbackLng: 'en',
               debug: true,
               nsSeparator: ':',
               keySeparator: '.',
               interpolation: {
                  escapeValue: false,
                  formatSeparator: ',',
                },
              react: {
                  wait: true,
                  useSuspense: false,
               },
            resources: {
                en: {
                     error: '{count, plural, one {Recording canceled.} other {Canceled # recordings.}}',
                     success: '{count, plural, one {Recording canceled.} other {Canceled recordings.}}',
                },
            },
        });


//Testing labels

i18n.t('error', {count : 1})
i18n.t('success', {count : 1})

//OUTPUT:  
// Recording canceled.
// Recording canceled.

i18n.('error', {count : 9})
i18n.t('success', {count : 9})

//OUTPUT: 
// {count, plural, one {Recording canceled.} other {Canceled # recordings.}} ---> EXPECTED OUTPUT: Canceled 9 recordings.
// Canceled recordings.

Smartphone (please complete the following information):

Android emulator pixel 30 api 30

Support Rich Text Formatting (`ignoreTag` to false)

๐Ÿš€ Feature Proposal

I would like to use Rich Text Formatting.

Motivation

As stated in Formatjs docs, "by allowing embedding XML tag we want to make sure contextual information is not lost when you need to style part of the string".

Example

t(key, {
  a: chunks => (
    <a
      class="external_link"
      target="_blank"
      href="https://www.example.com"
    >
      {chunks}
    </a>
  ),
  cta: chunks => <strong class="important">{chunks}</strong>,
})

Note

I am aware of the comment in i18next-icu code...

        // without ignoreTag, react-i18next <Trans> translations with <0></0> placeholders
        // will fail to parse, as IntlMessageFormat expects them to be defined in the
        // options passed to fc.format() as { 0: (children) => string }
        // but the replacement of placeholders is done in react-i18next
        fc = new IntlMessageFormat(res, lng, this.formats, { ignoreTag: true });

... but it would be nice to find a workaround, like adding { 0: (children) => string } or something.

ICU breaks 'replace' and 'replaceObjects: true' & XSS

When just reading up and trying to use i18next-icu, I failed to understand some details about it, that caused me to think i18next, or i18n-icu was broken/bugged software that would not work reliably. I've now traced it back to my understanding being off. The problems I faced:

  1. For safety I did not wan't to mix properties such as "lng" and "ns" with user generated interpolation dictionaries. So I put the user data in the replace option, to avoid polluting the main options. However, I now understand that IntlMessageFormat is called directly with options and it requires the replacements to be present at the root.
  2. replaceObjects does not work when using ICU. IntlMessageFormat can only work with strings. I expected the objects to be handled with i18next and the individual translations using ICU, however, it appears that ICU is used straight away, so the object is returned without nested fields being translated. This was quite disappointing to learn, as i18next-icu breaks this great feature of i18next itself, and it is documented nowhere.
  3. XSS is suddenly a risk, even though i18n's own options. Because if the user provided values contain "hacked" then this is in the output.

I really want to use ICU, because of CrowdIn plurals (https://support.crowdin.com/icu-message-syntax/?q=plural) but it seems that I can't use this module in the current state.

ICU will ignore the first blank in plural

๐Ÿ› Bug Report

Hello! I found the icu will ignore the first blank in plural, just like this demo. Please look at the { a} in key1. Is this a bug or just a feature? Is there any way to solve this problem? Because our i18n translations are auto-generated like key1, It is diffcullt to change the translation to like key2. Thanks!

image

To Reproduce

codepen

or

<div>
  <div>key1: {count} apple{num, plural, one { a} other{s two}} day, keep doctor away.</div><br />
  <div>1 apple: <div id="div11"></div></div><br />
  <div>2 apple: <div id="div12"></div></div><br />
</div>
<br />
<div>
  <div>key2: {count} {num, plural, one {apple a} other{apples two}} day, keep doctor away.</div><br />
  <div>1 apple: <div id="div21"></div></div><br />
  <div>2 apple: <div id="div22"></div></div><br />
</div>
const translation = {
  key1: '{count} apple{num, plural, one { a} other{s two}} day, keep doctor away.',
  key2: '{count} {num, plural, one {apple a} other{apples two}} day, keep doctor away.'
};

i18next.use(ICU).init({
  lng: "en",
  resources: {
    en: { translation }
  }
});


const div11 = document.getElementById('div11');
const div12 = document.getElementById('div12');
const div21 = document.getElementById('div21');
const div22 = document.getElementById('div22');

div11.innerText = i18next.t('key1', {count: 1, num: 1});
div12.innerText = i18next.t('key1', {count: 2, num: 2});
div21.innerText = i18next.t('key2', {count: 1, num: 1});
div22.innerText = i18next.t('key2', {count: 2, num: 2});

Expected behavior

We want the key1 and key2 have the same result.

Your Environment

  • runtime version: node v14.15.0, Crome 87
  • i18next version: 19.8.4
  • i18next-icu version: 1.4.2
  • os: Mac and Linux

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.