Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cli compile api: Allow to specify namespace/module type for createCompiledCatalog #285

Closed
dephiros opened this issue Aug 24, 2018 · 9 comments

Comments

@dephiros
Copy link
Contributor

Is your feature request related to a problem? Please describe.
I am planning to use jsLingui for a project at work. For various reasons and legacy codebase support, I cannot use jsLingui extraction mechanism and module import and need to inject json/objects as the catalogs for jsLingui in global
From @tricoder42 's response and after looking at the code a bit more, jsLingui core production module does not ship with the compiler and cannot use raw catalog.
Rather than using the raw catalog though, it would be very nice if I can use a compiled js object as the catalog to non-module JS code.
Currently the output for createCompiledCatalog is:

module.exports={languageData....}

What I would like to be able to do with createCompiledCatalog is:

window.translations={languageData}

Describe the solution you'd like
Similar to --namespace argument for messageformat.js CLI, we can add a namespace param to createCompiledCatalog(not sure namespace is the right name here; suggestions are welcomed):

  • if es6 is passed, then the output will be export default {}
  • if passed something that contains a '.'(we can be as fancy as we like about regex to validate the expression), then use that. ex: window.translations

I can put together a pull request sometimes this weekend or next week.

@dephiros dephiros changed the title Allow to specify namespace/module type for createCompiledCatalog cli compile api: Allow to specify namespace/module type for createCompiledCatalog Aug 24, 2018
@tricoder42
Copy link
Contributor

Hey @dephiros,
what about this:

cjs for module.exports (the default option)
es for export defaults
window.(.*) for adding window global
global.(.*) for adding node.js global

If you could also add this as a option to lingui compile and/or config to @lingui/conf with documentation, that would be amazing!

@dephiros
Copy link
Contributor Author

Hi @tricoder42 ,
I did not get a chance to get to this last weekend but started on familiarizing with the repo today. This is a very early draft of what I am planning to do w/o testing: #295. Since I am not familiar with the repo, I am posting early in case I am completely off track.

My next step is to:

I also notice that in local env, there are 11 tests fails in core and react packages. Is that expected?

@tricoder42
Copy link
Contributor

Hey @dephiros, PR looks great! What tests are failing? Everything on CI runs fine, even for me locally. What OS and node version do you have?

Btw I usually manually test CLI by running source files using babel-node:

cd packages/cli/test/fixtures/extract/
babel-node ../../../src/lingui-extract.js

It's dirty, but fast...

@dephiros
Copy link
Contributor Author

@tricoder42 , I can't seem to run babel-node like you mentioned. It kept giving me SyntaxError: Unexpected token import
Did you have to pass some configs?

Here is the failed tests:

 FAIL  packages/core/src/i18n.test.js (5.632s)
  ● Console

    console.warn packages/core/src/i18n.js:158
      Message catalog for locale "en" not loaded.
    console.warn packages/core/src/i18n.js:158
      Message catalog for locale "ar" not loaded.
    console.warn packages/core/src/i18n.js:158
      Message catalog for locale "en" not loaded.

  ● I18n › .use should return new i18n object with switched locales

    expect(received).toEqual(expected)

    Expected value to equal:
      "٢ الكتب"
    Received:
      "2 الكتب"

      171 |         other: "# الكتب"
      172 |       })
    > 173 |     ).toEqual("٢ الكتب")
          |       ^
      174 |
      175 |     const uae = i18n.use("ar", "en-UK")
      176 |     expect(

      at Object.<anonymous> (packages/core/src/i18n.test.js:173:7)

 PASS  packages/cli/src/api/catalog.test.js (6.347s)
 FAIL  packages/react/src/Select.test.js (7.407s)
  ● Categories › Plural › should use plural forms based on locales

    expect(received).toEqual(expected)

    Expected value to equal:
      "1.000"
    Received:
      "1,000"

      84 |       const t = () => node.find("Render").text()
      85 |
    > 86 |       expect(t()).toEqual("1.000")
         |                   ^
      87 |
      88 |       node.setProps({ value: 2500 })
      89 |       expect(t()).toEqual("2.500")

      at Object.<anonymous> (packages/react/src/Select.test.js:86:19)

  ● Categories › Plural › should use plural forms based on locales set on i18n

    expect(received).toEqual(expected)

    Expected value to equal:
      "1.000"
    Received:
      "1,000"

       98 |       const t = () => node.find("Render").text()
       99 |
    > 100 |       expect(t()).toEqual("1.000")
          |                   ^
      101 |
      102 |       node.setProps({ value: 2500 })
      103 |       expect(t()).toEqual("2.500")

      at Object.<anonymous> (packages/react/src/Select.test.js:100:19)

  ● Categories › Plural › should use plural forms based on language set on i18n

    expect(received).toEqual(expected)

    Expected value to equal:
      "1.000"
    Received:
      "1,000"

      112 |       const t = () => node.find("Render").text()
      113 |
    > 114 |       expect(t()).toEqual("1.000")
          |                   ^
      115 |
      116 |       node.setProps({ value: 2500 })
      117 |       expect(t()).toEqual("2.500")

      at Object.<anonymous> (packages/react/src/Select.test.js:114:19)

 PASS  packages/babel-plugin-transform-react/test/index.js
 PASS  packages/react/src/I18nProvider.test.js
 PASS  packages/babel-plugin-extract-messages/test/index.js (5.296s)
  ● Console

    console.warn packages/babel-plugin-extract-messages/src/index.js:128
      Missing message ID, skipping.
    console.warn packages/babel-plugin-extract-messages/src/index.js:129
      <Trans /> // this should be ignored
    console.warn packages/babel-plugin-extract-messages/src/index.js:128
      Missing message ID, skipping.
    console.warn packages/babel-plugin-extract-messages/src/index.js:129
      <Trans defaults="Missing ID" /> // this should be ignored
    console.warn packages/babel-plugin-extract-messages/src/index.js:128
      Missing message ID, skipping.
    console.warn packages/babel-plugin-extract-messages/src/index.js:129
      <Trans /> // this should be ignored
    console.warn packages/babel-plugin-extract-messages/src/index.js:128
      Missing message ID, skipping.
    console.warn packages/babel-plugin-extract-messages/src/index.js:129
      <Trans defaults="Missing ID" /> // this should be ignored
    console.warn packages/babel-plugin-extract-messages/src/index.js:171
      Missing message ID, skipping.
    console.warn packages/babel-plugin-extract-messages/src/index.js:172
      i18n._()
    console.warn packages/babel-plugin-extract-messages/src/index.js:171
      Missing message ID, skipping.
    console.warn packages/babel-plugin-extract-messages/src/index.js:172
      i18n._()

 PASS  packages/react/src/withI18n.test.js
 PASS  packages/cli/src/api/extract.test.js
 › 2 snapshots written.
 FAIL  packages/react/src/DateFormat.test.js
  ● DateFormat › should render using the given locales

    expect(received).toEqual(expected)

    Expected value to equal:
      "17/06/2017"
    Received:
      "2017-6-17"

      45 |       languageContext("en", "fr-FR")
      46 |     ).find("Render")
    > 47 |     expect(node.text()).toEqual("17/06/2017")
         |                         ^
      48 |   })
      49 |
      50 |   it("should render using the first recognized locale", function() {

      at Object.<anonymous> (packages/react/src/DateFormat.test.js:47:25)

  ● DateFormat › should render using the first recognized locale

    expect(received).toEqual(expected)

    Expected value to equal:
      "17/06/2017"
    Received:
      "2017-6-17"

      54 |       languageContext("en", ["unknown-locale", "fr-FR"])
      55 |     ).find("Render")
    > 56 |     expect(node.text()).toEqual("17/06/2017")
         |                         ^
      57 |   })
      58 |
      59 |   it("should render translation inside custom component", function() {

      at Object.<anonymous> (packages/react/src/DateFormat.test.js:56:25)

  ● NumberFormat › should render using the given locales

    expect(received).toEqual(expected)

    Expected value to equal:
      "42.000,00 €"
    Received:
      "€ 42,000.00"

      120 |       languageContext("en", "de-DE")
      121 |     ).find("Render")
    > 122 |     expect(node.text()).toEqual("42.000,00 €")
          |                         ^
      123 |   })
      124 |
      125 |   it("should render using the first recognized locale", function() {

      at Object.<anonymous> (packages/react/src/DateFormat.test.js:122:25)

  ● NumberFormat › should render using the first recognized locale

    expect(received).toEqual(expected)

    Expected value to equal:
      "42.000,00 €"
    Received:
      "€ 42,000.00"

      135 |       languageContext("en", ["unknown-locale", "de-DE"])
      136 |     ).find("Render")
    > 137 |     expect(node.text()).toEqual("42.000,00 €")
          |                         ^
      138 |   })
      139 |
      140 |   it("should render translation inside custom component", function() {

      at Object.<anonymous> (packages/react/src/DateFormat.test.js:137:25)

 FAIL  packages/core/src/dev/compile.test.js
  ● compile › should compile custom format for language=fr and locales=null

    expect(received).toEqual(expected)

    Expected value to equal:
      "0,1"
    Received:
      "0.1"

      94 |       function() {
      95 |         const number = prepare("{value, number}", language, locales)
    > 96 |         expect(number({ value: 0.1 })).toEqual(expectedNumber)
         |                                        ^
      97 |
      98 |         const percent = prepare("{value, number, percent}", language, locales)
      99 |         expect(percent({ value: 0.1 })).toEqual(expectedPercent1)

      at Object.<anonymous> (packages/core/src/dev/compile.test.js:96:40)

  ● compile › should compile custom format for language=fr and locales=fr-CH

    expect(received).toEqual(expected)

    Expected value to equal:
      "0,1"
    Received:
      "0.1"

      94 |       function() {
      95 |         const number = prepare("{value, number}", language, locales)
    > 96 |         expect(number({ value: 0.1 })).toEqual(expectedNumber)
         |                                        ^
      97 |
      98 |         const percent = prepare("{value, number, percent}", language, locales)
      99 |         expect(percent({ value: 0.1 })).toEqual(expectedPercent1)

      at Object.<anonymous> (packages/core/src/dev/compile.test.js:96:40)

 PASS  packages/react/src/Trans.test.js
 PASS  packages/babel-plugin-transform-js/test/index.js
 FAIL  packages/core/src/select.test.js
  ● Console

    console.warn packages/core/src/i18n.js:158
      Message catalog for locale "de" not loaded.

  ● plural › should convert to message format string

    expect(received).toEqual(expected)

    Expected value to equal:
      "لدي ١ كتاب"
    Received:
      "لدي 1 كتاب"

      85 |         locales: "ar-AS"
      86 |       })
    > 87 |     ).toEqual("لدي ١ كتاب")
         |       ^
      88 |
      89 |     expect(
      90 |       pDe({

      at Object.<anonymous> (packages/core/src/select.test.js:87:7)

 PASS  packages/cli/src/api/formats/po.test.js
 › 2 snapshots written.
 PASS  packages/cli/src/api/compile.test.js
 PASS  packages/cli/src/lingui-add-locale.test.js
 PASS  packages/react/src/Render.test.js
 PASS  packages/cli/src/lingui-init.test.js
 PASS  packages/react/src/format.test.js
 PASS  packages/react/src/mocks.test.js
 PASS  packages/core/src/mocks.test.js
 PASS  packages/conf/src/index.test.js
 PASS  packages/core/src/essentials.test.js
 PASS  packages/cli/src/api/locales.test.js
 PASS  packages/react/src/I18n.test.js
 PASS  packages/cli/src/api/detect.test.js
 PASS  packages/cli/test/index.js
 PASS  packages/core/src/t.test.js
 PASS  packages/cli/src/lingui-extract.test.js
 PASS  packages/react/src/i18nMark.test.js
 PASS  packages/core/src/i18nMark.test.js
 PASS  packages/loader/test/loader.test.js

=============================== Coverage summary ===============================
Statements   : 90.9% ( 1059/1165 )
Branches     : 85.6% ( 719/840 )
Functions    : 94.74% ( 216/228 )
Lines        : 91.31% ( 977/1070 )
================================================================================

Summary of all failing tests
 FAIL  packages/core/src/i18n.test.js (5.632s)
  ● I18n › .use should return new i18n object with switched locales

    expect(received).toEqual(expected)

    Expected value to equal:
      "٢ الكتب"
    Received:
      "2 الكتب"

      171 |         other: "# الكتب"
      172 |       })
    > 173 |     ).toEqual("٢ الكتب")
          |       ^
      174 |
      175 |     const uae = i18n.use("ar", "en-UK")
      176 |     expect(

      at Object.<anonymous> (packages/core/src/i18n.test.js:173:7)

 FAIL  packages/react/src/Select.test.js (7.407s)
  ● Categories › Plural › should use plural forms based on locales

    expect(received).toEqual(expected)

    Expected value to equal:
      "1.000"
    Received:
      "1,000"

      84 |       const t = () => node.find("Render").text()
      85 |
    > 86 |       expect(t()).toEqual("1.000")
         |                   ^
      87 |
      88 |       node.setProps({ value: 2500 })
      89 |       expect(t()).toEqual("2.500")

      at Object.<anonymous> (packages/react/src/Select.test.js:86:19)

  ● Categories › Plural › should use plural forms based on locales set on i18n

    expect(received).toEqual(expected)

    Expected value to equal:
      "1.000"
    Received:
      "1,000"

       98 |       const t = () => node.find("Render").text()
       99 |
    > 100 |       expect(t()).toEqual("1.000")
          |                   ^
      101 |
      102 |       node.setProps({ value: 2500 })
      103 |       expect(t()).toEqual("2.500")

      at Object.<anonymous> (packages/react/src/Select.test.js:100:19)

  ● Categories › Plural › should use plural forms based on language set on i18n

    expect(received).toEqual(expected)

    Expected value to equal:
      "1.000"
    Received:
      "1,000"

      112 |       const t = () => node.find("Render").text()
      113 |
    > 114 |       expect(t()).toEqual("1.000")
          |                   ^
      115 |
      116 |       node.setProps({ value: 2500 })
      117 |       expect(t()).toEqual("2.500")

      at Object.<anonymous> (packages/react/src/Select.test.js:114:19)

 FAIL  packages/react/src/DateFormat.test.js
  ● DateFormat › should render using the given locales

    expect(received).toEqual(expected)

    Expected value to equal:
      "17/06/2017"
    Received:
      "2017-6-17"

      45 |       languageContext("en", "fr-FR")
      46 |     ).find("Render")
    > 47 |     expect(node.text()).toEqual("17/06/2017")
         |                         ^
      48 |   })
      49 |
      50 |   it("should render using the first recognized locale", function() {

      at Object.<anonymous> (packages/react/src/DateFormat.test.js:47:25)

  ● DateFormat › should render using the first recognized locale

    expect(received).toEqual(expected)

    Expected value to equal:
      "17/06/2017"
    Received:
      "2017-6-17"

      54 |       languageContext("en", ["unknown-locale", "fr-FR"])
      55 |     ).find("Render")
    > 56 |     expect(node.text()).toEqual("17/06/2017")
         |                         ^
      57 |   })
      58 |
      59 |   it("should render translation inside custom component", function() {

      at Object.<anonymous> (packages/react/src/DateFormat.test.js:56:25)

  ● NumberFormat › should render using the given locales

    expect(received).toEqual(expected)

    Expected value to equal:
      "42.000,00 €"
    Received:
      "€ 42,000.00"

      120 |       languageContext("en", "de-DE")
      121 |     ).find("Render")
    > 122 |     expect(node.text()).toEqual("42.000,00 €")
          |                         ^
      123 |   })
      124 |
      125 |   it("should render using the first recognized locale", function() {

      at Object.<anonymous> (packages/react/src/DateFormat.test.js:122:25)

  ● NumberFormat › should render using the first recognized locale

    expect(received).toEqual(expected)

    Expected value to equal:
      "42.000,00 €"
    Received:
      "€ 42,000.00"

      135 |       languageContext("en", ["unknown-locale", "de-DE"])
      136 |     ).find("Render")
    > 137 |     expect(node.text()).toEqual("42.000,00 €")
          |                         ^
      138 |   })
      139 |
      140 |   it("should render translation inside custom component", function() {

      at Object.<anonymous> (packages/react/src/DateFormat.test.js:137:25)

 FAIL  packages/core/src/dev/compile.test.js
  ● compile › should compile custom format for language=fr and locales=null

    expect(received).toEqual(expected)

    Expected value to equal:
      "0,1"
    Received:
      "0.1"

      94 |       function() {
      95 |         const number = prepare("{value, number}", language, locales)
    > 96 |         expect(number({ value: 0.1 })).toEqual(expectedNumber)
         |                                        ^
      97 |
      98 |         const percent = prepare("{value, number, percent}", language, locales)
      99 |         expect(percent({ value: 0.1 })).toEqual(expectedPercent1)

      at Object.<anonymous> (packages/core/src/dev/compile.test.js:96:40)

  ● compile › should compile custom format for language=fr and locales=fr-CH

    expect(received).toEqual(expected)

    Expected value to equal:
      "0,1"
    Received:
      "0.1"

      94 |       function() {
      95 |         const number = prepare("{value, number}", language, locales)
    > 96 |         expect(number({ value: 0.1 })).toEqual(expectedNumber)
         |                                        ^
      97 |
      98 |         const percent = prepare("{value, number, percent}", language, locales)
      99 |         expect(percent({ value: 0.1 })).toEqual(expectedPercent1)

      at Object.<anonymous> (packages/core/src/dev/compile.test.js:96:40)

 FAIL  packages/core/src/select.test.js
  ● plural › should convert to message format string

    expect(received).toEqual(expected)

    Expected value to equal:
      "لدي ١ كتاب"
    Received:
      "لدي 1 كتاب"

      85 |         locales: "ar-AS"
      86 |       })
    > 87 |     ).toEqual("لدي ١ كتاب")
         |       ^
      88 |
      89 |     expect(
      90 |       pDe({

      at Object.<anonymous> (packages/core/src/select.test.js:87:7)


Snapshot Summary
 › 4 snapshots written from 2 test suites.

Test Suites: 5 failed, 27 passed, 32 total
Tests:       11 failed, 4 skipped, 180 passed, 195 total
Snapshots:   4 written, 51 passed, 55 total
Time:        24.166s
Ran all test suites.
error Command failed with exit code 1.

@dephiros
Copy link
Contributor Author

@tricoder42, I ended up using yalc and one of the sample project to test.

At this point, I think I added all the pieces(test, doc). However, I am running to this error where jest generates extra " on my machine in the snapshot (macOS high sierra).
Do you know how to get around that problem?
I also tried to manually edit the snapshot by hand but that would break the unit test on my machine; on circle CI, it still breaks with the message "Compared values have no visual difference"

@dephiros
Copy link
Contributor Author

@tricoder42, another update on the progress:

  • The pull request is ready
    • All new unit tests are passed. Turns out that I didn't configure Intellij to use the same configuration as the yarn run test command. I added a note on the contributing doc.
  • For existing unit tests that failed previously on my machine, this was caused by my node version does not have full icu enabled. I added this to the project setup instruction as well.

Please let me know if you have any additional feedbacks.

@tricoder42
Copy link
Contributor

@dephiros This is a really solid work! Thank you very much.

I went through PR and changed few things:

  • added more info to docs
  • renamed namespace to compileNamespace in config. I'm a bit worried that namespace is a bit general and might be confused for message namespace which some i18n libs use (and we might support in the future). For compile command, the argument is still called namespace: lingui compile --namepspace es

I'm just waiting for tests to be sure I haven't broke anything. Once it's done, I'll merge.

Thank you very much again!

@dephiros
Copy link
Contributor Author

Awesome! Thank you for your help as well

@tricoder42
Copy link
Contributor

Released in v2.6.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants