formatjs / formatjs-old

The monorepo home to all of the FormatJS related libraries.
https://formatjs.io/
156 stars 53 forks source link

[@formatjs/cli] Provide translation management functionality #588

Closed murar8 closed 4 years ago

murar8 commented 4 years ago

Is your feature request related to a problem? Please describe. Currently the cli only provides support for message extraction but it would be nice to have the option to do translation management using an official package. The functionality I'm looking for would be similar to what extract-react-intl-messages offers.

Describe the solution you'd like Create a subcommand like this:

formatjs manage [options] [files...]
It would then accept the following options:
--languages The array of languages for which to generate a translation.
--out-dir The output directory where JSON files will be generated, one for each locale.
--out-file Alternative to --out-dir, extract all messages in a single file grouped by locale.
... babel-plugin-react-intl configuration options.

It should also log some stats to the console like duplicate ids and maybe status of the translation files.

if it is something you would consider we could define the details and I would be happy to try and write a PR for this.

longlho commented 4 years ago

Yeah this is definitely something we're interested in but have not had the bandwidth to work on so PR's always welcome :)

murar8 commented 4 years ago

Ok so i worked through the code and started implementing the command and this is roughly what i'm going for:

Usage: formatjs <command> [flags]

Extract string messages from React components that use react-intl.
The input language is expected to be TypeScript or ES2017 with JSX.

Options:
  -v, --version                 output the version number
  -h, --help                    display help for command

Commands:
  help                          Show this help message.
  extract [options] [files...]  Extract messages and output them as a list of { id, defaultMessage, description }.
                                This mode of operation is just a wrapper around babel-plugin-react-intl
                                and will not apply any transformation to the extracted messages.
  manage [options] [files...]   Extract messages and output them as key-value pairs of id to message.
                                This mode of operation's output format is suitable to be imported in react and passed directly
                                to the IntlProvider component. Running this command will also add or delete entries
                                to existing translation files without overwriting the translated messages.
Usage: formatjs manage [options] [files...]

Extract messages and output them as key-value pairs of id to message. 
This mode of operation's output format is suitable to be imported in react and passed directly 
to the IntlProvider component. Running this command will also add or delete entries 
to existing translation files without overwriting the translated messages.

Options:
  --ignore <files>                                      List of glob paths to **not** extract translations from.
  --id-interpolation-pattern <pattern>                  If certain message descriptors don't have id, this `pattern` will be used
                                                        to automatically generate IDs for them. Default to `[contenthash:5]`.
                                                        See https://github.com/webpack/loader-utils#interpolatename for sample
                                                        patterns
  --module-source-name <name>                           The ES6 module source name of the React Intl package. Defaults to:
                                                        `"react-intl"`, but can be changed to another name/path to React Intl.
  --additional-component-names <comma-separated-names>  Additional component names to extract messages from, e.g:
                                                        `['FormattedFooBarMessage']`. **NOTE**: By default we check for the fact
                                                        that `FormattedMessage` is imported from `moduleSourceName` to make sure
                                                        variable alias works. This option does not do that so it's less safe.
  --extract-from-format-message-call                    Opt-in to extract from `intl.formatMessage` call with the same
                                                        restrictions, e.g: has to be called with object literal such as
                                                        `intl.formatMessage({ id: 'foo', defaultMessage: 'bar', description:
                                                        'baz'})` (default: false)
  -l --languages <comma-separated-codes>                Comma separated list of language codes to mantain. A translation entry will be
                                                        generated for every code in this list.
  -o --out-dir <path>                                   Output the extracted messages in JSON format in the 
                                                        directory,generating a [locale].json file for each specified locale.
  -f --out-file <path>                                  Output the extracted messages in a single JSON file containing an entry for
                                                        each locale.
  -h, --help                                            display help for command

Now there are a couple of details I would like to discuss before going forward with the implementation:

  1. It is not clear to me as to what the --remove-default-message option actually does since we are using babel just for extraction?

  2. It does not look like it is possible to pass multiple patterns to --ignore since neither comma or space separation work but maybe I'm missing something? Another option for file exclusion would be to use the globby package that supports multiple patterns so ignoring would go something like this: formatjs manage src/**/*.js !src/**/*.test.js

Please tell me if you have any other considerations.

longlho commented 4 years ago

hmm I'm not sure about the key-value format because that doesn't capture description which is very important for translators.

--remove-default-message isn't necessary as you mentioned. --ignore rn just proxy straight to glob so I don't think multiple patterns are supported.

murar8 commented 4 years ago

I understand but the main use case i envisioned for the tool would be to just extract the messages in a format where translations can be filled in and directly imported in code, and keeping metadata inside each translation file would complicate the workflow in my opinion. Since I noticed this is a common use case for smaller projects I thought it would be nice to have that feature integrated in the repo without having to install and configure babel and some random translation management package but if what you have in mind is more sophisticated maybe it is more appropriate I publish it as a separate package?

longlho commented 4 years ago

hmm if u're publishing it as a separate package wouldn't https://github.com/akameco/extract-react-intl-messages be sufficient? I think the aspect of managing multiple locales might be valuable but not the output schema.

murar8 commented 4 years ago

Ok so I ended up releasing it as an external package mainly because I wanted to gain some familiarity with CI pipelines and publishing to npm. To answer your question yes the tool I built does not add much value to existing utilities besides allowing users to extract translations without configuring babel. I have no doubt You can make a much more informed decision than me about the output schema but that's just not what I need at the moment.

longlho commented 4 years ago

kk sgtm!