GithubHelp home page GithubHelp logo

facebook / fbt Goto Github PK

View Code? Open in Web Editor NEW
3.8K 44.0 176.0 14.44 MB

A JavaScript Internationalization Framework

Home Page: https://facebook.github.io/fbt

License: MIT License

JavaScript 98.78% CSS 0.58% HTML 0.01% TypeScript 0.02% Java 0.35% Objective-C 0.04% Objective-C++ 0.07% Ruby 0.08% Shell 0.07%
javascript internationalization i18n framework

fbt's Issues

Typescript support

Manifest and maybe other cli should support .ts and .tsx files

I think the transform will just work as babel 7 supports typescript

Need to support unit tests for open-source

The unit tests we have can only be run in our internal test infra.

We need to create a new Jest config to make it testable in a stand-alone environment (outside FB infra).

Ideally, it could then be run on Travis externally. A nice to have for later.

expand on the options object to show the demonstrated translation?

Currently the landing page at https://facebookincubator.github.io/fbt/ shows the english text text with a descriptor eg, an object with translation information keyed on that eg, and then a resultant translated snippet. However, the translation in the translated snippet is nowhere to be found in the translation object, so even if it's just to show an except of how things work, it's a good idea to show that there is a relation between all three aspects: currently the translated snippet does not appear to be based on anything related to the other two bits of code shown.

Improve CLI ergonomics

There are currently 3 separate CLI scripts to use (manifest, collection, translation), all requiring different CLI arguments and coordination. We should simplify this per the following:

  • One CLI script to rule them all with
  • A command for each existing script and
  • The ability to provide any given command line argument/option in via a configuration file
  • Similarly any options that babel-plugin-fbt takes should be readable from this config file.

Provide translation format interop

Hey folks!

I got 2 important questions to consider this in our next project:

  • Does this somehow support exporting to .mo files and vice versa ?
  • If not is there any open source tooling that you're using for translators ?

Cheers

FBT is a bad JSX-transform citizen

Currently the babel-plugin-fbt transform needs to see untransformed JSX <fbt> nodes before any other JSX babel transforms to perform its transpilation. This is non-standard, and we should fix it. Essentially, enable the same JSX code, but post-JSX transform and accept something like

React.createElement("fbt", ...)

and still turn this into

fbt._(...)

at runtime

In effect, the transform should be able to work the same whether there's another transform layer in front or not.

Publish modules to npm

We should publish transforms and runtime to npm to enable easier integration into existing web-apps. Within this process, we should fix the haste "global" paths in our runtime require statements and convert to the CommonJS relative file-paths (like our transforms).

[docs] add docs of how to integrate with an existing react app

it would be great to have a step by step tutorial on docs of how to setup fbt in an existing React app project

which packages should we install?
how should we modify our babel config?
should we modify our webpack config?
how to translate new generated hash keys?

FBT default import has issues with ESModules/CommonJS interop

🐛 Bug Report

I'm working in an ES2017 codebase compiled with TypeScript, Babel, and webpack. It seems that in certain contexts, using the default import of FBT fails because babel-plugin-fbt says the variable fbt is not bound when using the fbt() syntax in code. Examining the value of the import, is an object with this structure:

{
  __esModule: true,
  FbtTranslations: { /* ... */ },
  GenderConst: { /* ... */ },
  default: f (),
  fbt: f (),
  init: f (e),
}

I'm not sure which step of tooling is responsible for making the default export an object.

I've confirmed that a reliable workaround is to write const { fbt } = require('fbt') rather than const fbt = require('fbt').

I believe that the fault lies in babel-plugin-fbt, since I am able to use the default exports of other libraries without issue.

To Reproduce

Not certain what the minimal replication case is.

Expected behavior

When using TypeScript and/or webpack, FBT should work reliably when using the default export.

envinfo

 System:
    OS: macOS Sierra 10.12.6
    CPU: (8) x64 Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
    Memory: 288.96 MB / 16.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 12.12.0 - ~/.nvm/versions/node/v12.12.0/bin/node
    Yarn: 1.19.1 - /usr/local/bin/yarn
    npm: 6.11.3 - ~/.nvm/versions/node/v12.12.0/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman

Migration Website to Docusaurus 2 Alpha

Hi there! The Docusaurus team is currently developing Docusaurus 2 and are almost done with an MVP that doesn't include translations and versioning features, which means there's feature parity with your website's current usage of Docusaurus.

Docusaurus 2 brings about many improvements:

  • Client-side rendering with prerendering (site renders without JavaScript!)
  • More flexible appearance - Customizable layouts, CSS modules, etc
  • Embeddable interactive React components within markdown via MDX

I will be your POC in helping you throughout the migration process. Let me know what you think!

cc @yangshun @endiliey

Code splitting translation

First of all, thanks for making fbt open source! 🙏

Currently the transform script only outputs a single file, which in the application gets passed to the fbt's init function. This means that we need to load all translations at once! Are there any plans on supporting generating multiple translation files that could then be dynamically loaded by fbt when needed? For starters it would for example be nice to split translations on locale.

For cross-platform use 'shx find' from npm package 'shx' instead unix util 'find'

For cross-platform do not use unix util find
You can use npm package shx
'yarn manifest' failed in windows

PS Z:\sources\react\fbt\demo-app> yarn manifest
yarn run v1.12.3
$ babel-node ../transform/babel-plugin-fbt/bin/manifest --src src
�� ������ 䠩�: '*$FbtEnum.js'
child_process.js:645
    throw err;
    ^

Error: Command failed: find . -type f -iname '*$FbtEnum.js'
�� ������ 䠩�: '*$FbtEnum.js'

    at checkExecSyncError (child_process.js:602:13)
    at execSync (child_process.js:642:13)
    at Object.<anonymous> (Z:\sources\react\fbt\transform\babel-plugin-fbt\bin\manifest.js:76:3)
    at Module._compile (module.js:653:30)
    at Module._compile (Z:\sources\react\fbt\node_modules\pirates\lib\index.js:83:24)
    at Module._extensions..js (module.js:664:10)
    at Object.newLoader (Z:\sources\react\fbt\node_modules\pirates\lib\index.js:88:7)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
PS Z:\sources\react\fbt\demo-app>

The translate script is flaky

Sometimes, calling the translate script produces the following error:

  Error: EAGAIN: resource temporarily unavailable, read
  at Object.readSync (fs.js:498:3)
  at tryReadSync (fs.js:332:20)
  at Object.readFileSync (fs.js:369:19)
  at Object.<anonymous> (/node_modules/babel-plugin-fbt/bin/translate.js:209:31)

Question on plurals

Hi! Thanks for open sourcing this. Looks exciting!

Plural handling jumped out at me as very basic:
https://facebookincubator.github.io/fbt/docs/plurals

As is, it looks like a simplistic-yet-very-specific one/many handling with support for showing a counter.
Since fbt is used at Facebook (a product with a pretty involved translation) I'm curious if that is actually enough for Facebook itself?

For context, several languages (Russian for example) have many types of plurals. The ICU message syntax is my go-to for supporting these cases:
http://userguide.icu-project.org/formatparse/messages (it is used by FormatJS so should be familiar to users of formatjs projects).

IntlNumberType.get(locale) Do not work with shorts locales

I have interesting bug, I use locales like('en', 'ru')

_getNumberModuleForLang always return default value IntlCLDRNumberType01

Because:

locale = 'ru';

getNumberVariations() 
    => IntlNumberType.get(locale) 
        => FBLocaleToLang.get(locale) // return ''
----------------------------------^^^ here bug

Snippet:

(()=>{
    const _locToLang = {
        "cx_PH": "ceb",
        "ck_US": "chr",
        "fb_AA": "en",
        "fb_AC": "en",
        "fbt_AC": "en",
        "fb_HA": "en",
        "fb_AR": "ar",
        "fb_HX": "en",
        "fb_LS": "en",
        "fb_LL": "en",
        "fb_RL": "en",
        "fb_ZH": "zh",
        "tl_PH": "fil",
        "sy_SY": "syr",
        "qc_GT": "quc",
        "tl_ST": "tlh",
        "gx_GR": "grc",
        "qz_MM": "my",
        "eh_IN": "hi",
        "cb_IQ": "ckb",
        "zz_TR": "zza",
        "tz_MA": "tzm",
        "sz_PL": "szl",
        "bp_IN": "bho",
        "ns_ZA": "nso",
        "fv_NG": "fuv",
        "em_ZM": "bem",
        "qr_GR": "rup",
        "qk_DZ": "kab",
        "qv_IT": "vec",
        "qs_DE": "dsb",
        "qb_DE": "hsb",
        "qe_US": "esu",
        "bv_DE": "bar",
        "qt_US": "tli",
        "nh_MX": "nah",
        "tq_AR": "tob",
        "fn_IT": "fur",
        "lr_IT": "lij"
    };

    const FBLocaleToLang = {
        get: function(locale) {
            return _locToLang[locale] || locale.substring(0, locale.indexOf('_'));
        },
    };

    
    return FBLocaleToLang.get('en'); // return ""
    return FBLocaleToLang.get('ru'); // return ""
})();

SSR support

Hi, quick question. I didn't see on docs if fbt is mean to be used on a react server side rendered (SSR). It is? :)

Thanks for all the work!

FBT Enums only work as `require` statements

The following blows up because the enum isn't required via require(...), but instead uses import

import { fbt } from 'fbt-runtime'
import CategoriesEnum from './Categories$FbtEnum'
function category(listing) {
  return (
    <span>
      <fbt desc="Category">
        <fbt:enum enum-range={CategoriesEnum} value={listing.category} />
      </fbt>
    </span>
  )
}

export default category

[babel-plugin-fbt] in conflict with "react-hot-loader/babel" : TypeError: Property value expected type of string but got null

When I run next command:

node ../node_modules/babel-plugin-fbt/bin/collectFBT.js --pretty  --json-input  < i18n/src-manifest.json

I get an error:

src/features/usersPage/Page/index.js:
	TypeError: Property value expected type of string but got null

/home/i/all-work/synergeto/admin-ui/node_modules/babel-plugin-fbt/bin/collectFBT.js:131
    throw new Error(`Failed in ${errCount} files`);
    ^

Error: Failed in 4 files
    at writeOutput (/home/i/all-work/synergeto/admin-ui/node_modules/babel-plugin-fbt/bin/collectFBT.js:131:11)
    at ReadStream.<anonymous> (/home/i/all-work/synergeto/admin-ui/node_modules/babel-plugin-fbt/bin/collectFBT.js:169:5)
    at ReadStream.emit (events.js:203:15)
    at endReadableNT (_stream_readable.js:1129:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)

A babel config to fix this problem:

const fbtEnumManifest = require('./.i18n/enum-manifest.json');

const presets = ['@exeto/babel-preset-react'];
const plugins = [
  ['babel-plugin-fbt', { fbtEnumManifest }],
  'babel-plugin-fbt-runtime',
];

// To fix problem with Fbt
+if (process.env.NODE_ENV === 'development') {
+  plugins.push('react-hot-loader/babel');
+}

module.exports = {
  presets,
  plugins,
};

Consider exposing a macro.

Sorry if this has been brought up somewhere before.
Would you consider using babel-plugin-macros for babel-plugin-fbt? It looks like a good fit for an imperative tool and would allow adoption in create-react-app projects. You could probably rework the demo a bit to use it and be a little more concise.

Script collectFBT.js failed with a human unreadable error

When you forgot add a many prop:

<fbt:plural {/*many="seals"*/} showCount="ifMany" count={Number(count)}>
              a seal
</fbt:plural>

You will see an error like this:

src/Plurals/index.js:
	TypeError: Cannot read property 'start' of undefined
/home/i/open-source/fbtDemo/node_modules/babel-plugin-fbt/bin/collectFBT.js:156
    throw new Error(`Failed in ${errCount} files`);
    ^

Error: Failed in 1 files
    at writeOutput (/home/i/open-source/fbtDemo/node_modules/babel-plugin-fbt/bin/collectFBT.js:156:11)
    at ReadStream.<anonymous> (/home/i/open-source/fbtDemo/node_modules/babel-plugin-fbt/bin/collectFBT.js:194:5)
    at ReadStream.emit (events.js:203:15)
    at endReadableNT (_stream_readable.js:1145:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)

Next.js babel preset

1) Integration with Next.js (TypeScript)

I don't know how can I fix the next problem:

import * as React from 'react';

// @ts-ignore : 'fbt' is declared but its value is never read.
import fbt from 'fbt'; 

console.log(fbt); // ( 1 ) 

// @ts-ignore
const node = <fbt desc='desc-text'>Some text</fbt>;
  1. When I commented on this line I get next build error: fbt is not bound. Did you forget to require('fbt')

Did It mean that webpack bundle remove unused import before babel transpilation?

2) Empty childParentMappings:{}

And node_modules/babel-plugin-fbt/bin/collectFBT.js couldn't collect any phrases from code


DEMO Next.js App

dependencies": {
    "fbt": "^0.9.51",
    "babel-plugin-fbt": "^0.9.12",
    "babel-plugin-fbt-runtime": "^0.9.1",
}

Unsure about where translation files come from

I'm trying to understand the fbt demo app a little better. I think I understand what most scripts are doing, but I don't understand where any of the ./translations/*.json files come from. They seem to be auto generated due to there being base64 strings as keys.

Are these json files auto generated? Or compiled by hand?

(to be clear - I'm not asking about the actual translated text, I'm asking about how these files get generated for me to fill in with my own translations for phrases 😊)

`intlList` has incorrect relative imports in npm package, can't require with webpack

In the npm package for fbt, 0.9.5, in node_modules, fbt/lib/intlList.js has this for line 25:

var React = require("./React");

However, there's no React in the lib folder so with webpack it fails to resolve require('fbt/lib/intlList'). In the source file though, https://github.com/facebookincubator/fbt/blob/master/runtime/shared/intlList.js, there's an absolute import for React, const React = require('React').

Is this an error? And if so can we update the version of the npm package?

JSX Support short bool syntax

For next example

<fbt desc="" doNotExtract>Test</fbt>

I get this error:

    TypeError: Cannot read property 'type' of null

      at node_modules/babel-plugin-fbt/FbtUtil.js:140:15
          at Array.forEach (<anonymous>)
      at getOptionsFromAttributes (node_modules/babel-plugin-fbt/FbtUtil.js:130:18)
      at PluginPass.JSXElement (node_modules/babel-plugin-fbt/index.js:153:13)
      at newFn (node_modules/@babel/traverse/lib/visitors.js:193:21)
      at NodePath._call (node_modules/@babel/traverse/lib/path/context.js:53:20)
      at NodePath.call (node_modules/@babel/traverse/lib/path/context.js:40:17)
      at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:88:12)
      at TraversalContext.visitQueue (node_modules/@babel/traverse/lib/context.js:118:16)
      at TraversalContext.visitSingle (node_modules/@babel/traverse/lib/context.js:90:19)
// this example work fine
<fbt desc="" doNotExtract={true}>Test</fbt>
{
    "babel-plugin-fbt": "^0.9.14",
}

Provide event hooks into the FBT API.

🚀 Feature Proposal

Please provide an event emitter as part of FBT, so that developers can gain insights into how FBT operates under the hood.

Motivation

FBT currently offers very little in the way of reporting what work goes on behind the scenes. For instance, how can a developer know if a provided string is being translated at runtime? Making fbt an event emitter with hooks for parts of the string substition process (language lookup, string lookup, etc.) would make the library easily introspectable. It would allow teams to collect statistics and determine where translations are missing, among other potential features.

Example

This example would show how Sentry could be triggered when a translation is missing.

const fbt = require('fbt');
const Sentry = require('@sentry/browser');
fbt.on('missingTranslation', (language, hash) => {
  Sentry.withScope(scope => {
    scope.setExtras({ hash, language });
    Sentry.captureMessage('Missing translation');
  });
});

Pitch

Potential users would be incentivized to choose FBT over competing solutions with better real-time data reporting. Executives want assurance that chosen software solutions are reliable. Without being able to inspect FBT as it works in real-time, developers would have to spend time writing more code and tooling to ensure that their translation system works as expected.

Document the common string API

🚀 Feature Proposal

babel-plugin-fbt allows developers to use an attribute common to FBT calls which use JSX syntax. However, no documentation exists on https://facebookincubator.github.io/fbt/ for this feature.

Motivation

It is not clear how or why to use the common string API.

Example

This feature would allow organizations or developers to define a set of frequently occurring strings which are reusable in FBT

Pitch

The common string API could be a productivity boon to teams which have strings with specific meanings that need to be conveyed in a centralized location.

Does fbt support html strings?

Hey, thanks for the nice package,

I have a question, does fbt support html string string?
like in react-intl theres formatHTMLmessage method that accept html element like:
formatHTMLmessage ('id','<span>test html string</span>')

does fbt support this?

Display translation progress

Hi! I think we need to keep track of both translated/untranslated items to ensure the app is properly translated.

I believe you guys doing automate this copy & paste(source_strings.json to trasnlation_input.json) process and maybe already planned to handle this issue while implementing that already, but I'm opening this issue for just clarification.

Fix Non-Standard JSX space normalization

<fbt> strips any newlines and spaces that sit in between constructs that don't neighbor raw text. This is at odds with what is typically produced by any other native DOM markup. This was originally to maintain parity with PHP/XHP/Hack's , but that decision is now in question. Especially in light of open-sourcing this to the greater JS community, we should try and support an API that is intuitive lacks surprises.

<fbt desc="d">
  <span>
    Where do
  </span>
  <b>spaces</b>
  <i>go?</i>
  Good
 <i>question</i>
 !
</fbt>

produces the following runtime

  fbt._("{=Where do}{=spaces}{=go?} Good {=question} !",[...])

Compare this with what would have been produced in a browser:
Where do spaces go? Good question !

Rerender problem

How to solve the next problem:

// @flow
import React, { useState, useCallback } from 'react';
import fbt, { IntlViewerContext } from 'fbt';

const Links = () => {
  return <fbt desc="test">Text link</fbt>;
};

const App = () => {
  const setState = useState({})[1];
  const onClick = useCallback(() => {
    IntlViewerContext.locale = Math.random() > 0.5 ? 'en_GB' : 'de_DE';
    setState({});
  }, [setState]);

  return (
    <div onClick={onClick}>
      <fbt desc="test">Title</fbt>
      <Links />
      {/*
         rerender a `<Links/>` component never would call
         and text does not change when set new locale
      */}
    </div>
  );
};

yarn manifest出现错误?

你好,我按照这边提供的命令初始化该项目,但是yarn install之后到了yarn manifest生成文件时出现问题,请问能帮我看一下这是有什么问题导致的吗?
QQ截图20190403111654

support StringLiteral in fbt:enum

I was running a codemod to convert <div prop={"value"} /> to <div prop="value" />, and I ran into a bug because the transform doesn't handle a string literal value property, only a string within a jsx expression container.

To be specific, the transform errors out if you change

<fbt:enum
  enum-range={EnumName}
  value={'Value'}
/>

to

<fbt:enum
  enum-range={EnumName}
  value="Value"
/>

Consolidate pronoun constants

Pronouns can be consolidated into the following values (as opposed to the 13 we have currently).

pronoun          subject possessive reflextive   object
NOT_A_PERSON     "they"  "their     "themself"   "this"
UNKNOWN_SINGULAR "they"  "their"    "themself"   "them"
UNKNOWN_PLURAL   "they"  "their"    "themselves" "them"
MALE             "he"    "his"      "himself"    "him"
FEMALE           "she"   "her"      "herself"    "her"

Docs: Broken links on website footer

On footer all the links are using the docUrl method that is adding the language on the url:

  • /fbt/docs/en/api_intro
  • /fbt/docs/en/getting_started

However, these links are not correct. Getting an 404 error.

Although maybe in the future will be support for many languages, I think is better to change this invalid links for the valid links right now.

[babel-plugin-fbt] Invalid deploy, fbjs is missing in dependencies

In repo:

https://github.com/facebookincubator/fbt/blob/2add25c108c601a11088c10e5c8f808b8ad62897/transform/babel-plugin-fbt/package.json#L14

In npm:

image

Result this problem:

node ../node_modules/babel-plugin-fbt/bin/collectFBT.js 


internal/modules/cjs/loader.js:638
    throw err;
    ^

Error: Cannot find module 'fbjs/lib/invariant'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
    at Function.Module._load (internal/modules/cjs/loader.js:562:25)
    at Module.require (internal/modules/cjs/loader.js:690:17)
    at require (internal/modules/cjs/helpers.js:25:18)
    at Object.<anonymous> (/home/i/all-work/synergeto/node_modules/babel-plugin-fbt/fbt-shift-enums.js:19:19)
    at Module._compile (internal/modules/cjs/loader.js:776:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)

Remove FbtCommonConstants from babel-plugin-fbt

🚀 Feature Proposal

babel-plugin-fbt currently contains the following dictionary of Facebook-specific strings in the library, used for the common API: https://github.com/facebookincubator/fbt/blob/cf5743af96e48ce49cda9f3258c5d1102684f1b7/packages/babel-plugin-fbt/FbtCommonConstants.js

Developers should be able to register their own set of common strings, instead.

Motivation

This proposal relates to #108. For the common string API to be useful, developers need to be able to say which strings are constant.

Example

A developer could provide a JSON file which contains a dictionary of common strings. For instance, this might be part of the collectFBT command:

node ./node_modules/babel-plugin-fbt/bin/collectFBT --commonSrc ./config/i18n/commonStrings.json --manifest < .fbt/src_manifest.json > .fbt/source_strings.json

Pitch

This feature would be useful for the same reason #108 would be useful: it would empower teams to do more with FBT.

Cannot run demo app

When I run yarn install on windows, I get:

error An unexpected error occurred: "ENOTDIR: not a directory, scandir 'D:\fbt\demo-app\node_modules'".

I think it has to do with there being an existing file/link (not sure what that is) in the directory. If anyone can guide me to it's purpose, would be happy to send in a PR that resolves this

Provide hooks for logging instead of mocks

🚀 Feature Proposal

FBT currently uses a mock called FBTLogger to log impressions of translations: https://github.com/facebookincubator/fbt/blob/3a5441708ca6b71c2c18fe5a952d1058a22306d1/runtime/shared/fbt.js#L28

This logging system should be configurable by developers, similar to (or possibly in the same system as) #109.

Motivation

Similar to #109, developers and other stakeholders may want to know which translations are being used in a given web app. This could be used to trigger engineer notifications for when a translation is missing, or to log an occurrence for a special event.

Example

Here's an example of how a logging API might work:

const fbt = require('fbt');

const consoleLogger = {
  logImpression(hash) {
    console.log('i18n hash lookup:', hash);
  },
};

fbt.setLogger(consoleLogger);

Pitch

Observability is an important facet of any mature web application. Without the ability to respond to changes in the internals of FBT, the library may not be attractive to potential stakeholders and less useful to developers.

Auto-wrapping is broken for non-textual children (fbt:*, template literals, etc)

This is fully evident even in the example app:

    <fbt desc="...">
      <fbt:param name="name" gender={this.state.ex1Gender}>
        <b className="padRight">{this.state.ex1Name}</b>
      </fbt:param>
      has shared
      <a className="neatoLink" href="#">
        <fbt:plural
          many="photos"
          showCount="ifMany"
          count={this.state.ex1Count}>
          a photo
        </fbt:plural>
      </a>
      with you
    </fbt>

Extracts to

  {
      "hashToText": {
        "PqPPir8Kg9xSlqdednPFOg==": "{name} has shared {=a photo} with you"
      },
      "jsfbt": {
        "t": {
          "*": "{name} has shared {=a photo} with you"
        },
        "m": [
          {
            "token": "name",
            "type": 1
          }
        ]
      }
    },
    {
      "hashToText": {
        "/gj3gwqx1z8Xw233oZgOpQ==": "{number} photos",
        "8UZCD6gFUKN+U5UUo1I3/w==": " a photo"
      },
      "desc": "In the phrase: \"{=} has shared {=a photo} with you\"",
      "jsfbt": {
        "t": {
          "*": "{number} photos",
          "_1": " a photo"
        },
        "m": [
          {
            "token": "number",
            "type": 2,
            "singular": true
          }
        ]
      }
    }

Notice both the "{=}" token and the {=a photo} token in the description:

'In the phrase: "{=} has shared {= a photo} with you"'

So two things wrong here. {=} should be {name} AND the {number} photos variant of the <fbt:plural> instance needs its own description such that its token corresponds to the inner text:

'In the phrase: "{name} has shared {=[number] photos} with you"'

There should be two separate outer strings here (not one):

"{name} has shared {=a photo} with you"
"{name} has shared {=[number] photos} with you"

and inner-strings should have separate descriptions:

'In the phrase: "{name} has shared {=a photo} with you"'
'In the phrase: "{name} has shared {=[number] photos} with you"'

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.