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

i18nline with Preact-CLI #6

Closed
chuikoffru opened this issue Jul 4, 2017 · 20 comments
Closed

i18nline with Preact-CLI #6

chuikoffru opened this issue Jul 4, 2017 · 20 comments

Comments

@chuikoffru
Copy link

Hi, I create project by Preact-CLI

Next, npm i preact-i18nline i18nline

I create i18n/en.json

Add strings to package.json:

{ "i18n": { "plugins": [ "preact-i18nline" ], "directories" : "src", "patterns" : ["**/*.js", "**/*.jsx"], "outputFile" : "i18n/en.json" }, "scripts": { "trlt": "i18nline export" } }

Run npm run trlt
And...

i18nline export

env: node\r: No such file or directory
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn
npm ERR! chuikoff@1.0.0 trlt: i18nline export
npm ERR! spawn ENOENT

@Download
Copy link
Owner

Download commented Jul 4, 2017

Does not ring a bell for me. Unfortunately I have not yet tried preact-18nline i.c.w. preact-cli.
Let me know if you figure it out.
Also, what is npm run trlt?

@chuikoffru
Copy link
Author

chuikoffru commented Jul 4, 2017

@Download

Also, what is npm run trlt?

In package.json:
"scripts": { "trlt": "i18nline export" } }

@Download
Copy link
Owner

Download commented Jul 5, 2017

Ay yes sorry should have seen that.

@Download
Copy link
Owner

I think I fixed the issue with the env: node\r: No such file or directory. Still needs some testing though.

@Download
Copy link
Owner

Download commented Apr 5, 2018

Hi @chuikoffru
I think this issue is now fixed in v2. Also, I added some docs to better explain how to setup a project. It even has a section specifically for Preact CLI.

I'm closing this issue, but feel free to comment or open a new issue if it's not fixed or you have other problems. Thanks for trying preact-i18nline and for taking the time to report issues. Much appreciated!

@Download Download closed this as completed Apr 5, 2018
@yduman
Copy link

yduman commented Apr 17, 2018

Hi @Download ,

I recently discovered an issue, when running npm test on a project created with Preact CLI. It has some problems with the I18n.import function, which is autogenerated. Here the output of Jest:

$ ../../node_modules/jest/bin/jest.js
 FAIL  .\header.test.js
  ● Test suite failed to run

    C:\Projects\preact-test\src\i18n\index.js:12
                case 'en':return import( /* webpackChunkName: 'i18n.en'
*/'./en.json');
                                 ^^^^^^

    SyntaxError: Unexpected token import

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:305:17)
      at Object.<anonymous> (src/components/meta-nav/index.js:2:13)
      at Object.<anonymous> (src/components/header/index.js:5:16)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        1.786s
Ran all test suites.

@Download
Copy link
Owner

SyntaxError: Unexpected token import

This suggests the code is not being transpiled by Babel correctly. Can you post the commands you used to create this project (so I can try to reproduce)? And did you create/change preact.config.js and if so, can you post that here as well?

Can you try to create a preact project from scratch and follow the steps for setting up a project as outlined here and here? Does this work for you?

Thank you for trying out preact-i18nline and for taking the time to report feedback. It is much appreciated!

@Download Download reopened this Apr 19, 2018
@yduman
Copy link

yduman commented Apr 20, 2018

Project was created with: preact create default myApp
preact.config.js (should be the same as documented):

export default (config, env, helpers) => {
  // Use Preact CLI's helpers object to get the babel-loader
  let babel = helpers.getLoadersByName(config, 'babel-loader')[0].rule;
  // Update the loader config to include preact-i18nline
  babel.loader = [
    { // create an entry for the old loader
      loader: babel.loader,
      options: babel.options
    },
    { // add the preact-i18nline webpack loader
      loader: 'preact-i18nline/webpack-loader'
    }
  ];
  // remove the old loader options
  delete babel.options;
};

I will create another project from scratch later the day, because I am currently at work.

Thanks for reaching out!

@yduman
Copy link

yduman commented Apr 20, 2018

So these are the steps I did, to recreate the issue.

  • preact create default myApp
  • cd myApp && npm i -S i18nline preact-i18nline
  • created the script "i18n": "i18nline synch" in package.json
  • added preact.config.js (same as documented in README)
  • added translate="yes" on the h1 element of the header component under components/header
  • ran npm run i18n
  • imported the index file into app.js: import I18n from "../i18n"
  • and here is the index file of the header component:
import { h, Component } from 'preact';
import { Link } from 'preact-router/match';
import style from './style';
import I18n from "../../i18n";

export default class Header extends Component {
	constructor(props) {
		super(props);
		this.state = {
			key: 0
		}
	}

	translate() {
		I18n.changeLocale("en");
	}

	render() {
		I18n.on("change", locale => {
			// to avoid this.forceUpdate()
			this.setState({ key: Math.random() });
		});

		return (
			<header class={style.header}>
				<h1 translate="yes">Preact App</h1>
				<nav>
					<Link activeClassName={style.active} href="/">Home</Link>
					<Link activeClassName={style.active} href="/profile">Me</Link>
					<Link activeClassName={style.active} href="/profile/john">John</Link>
					<button onclick={this.translate}>translate</button>
				</nav>
			</header>
		);
	}
}
  • then, I ran ../../node_modules/jest/bin/jest.js under src/tests. The call is like this, since there is a bug with the created npm run test command (issue is filed in the preact-cli repo). So after the call the same message appears:
$ ../../node_modules/jest/bin/jest.js
 FAIL  .\header.test.js
  ● Test suite failed to run

    C:\Users\yduman\Desktop\myApp\src\i18n\index.js:12
                case 'en':return import( /* webpackChunkName: 'i18n.en' */'./en.json');
                                 ^^^^^^

    SyntaxError: Unexpected token import

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:305:17)
      at Object.<anonymous> (src/components/header/index.js:4:13)
      at Object.<anonymous> (src/tests/header.test.js:2:15)

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        1.701s
Ran all test suites.

Hope this helps :)

@Download
Copy link
Owner

Thanks this does help.

One question still though. If you just run the project with npm start, does it fail with the same error or what happens? And does import work with Jest if i18nline is not used?

@yduman
Copy link

yduman commented Apr 23, 2018

  • npm start works.
  • import worked with Jest, when i18nline wasn't used.

@Download
Copy link
Owner

This issue baffles me. import has nothing to do with i18nline really. It's just a generic ES6 feature.

I am not convinced there is an issue with i18nline here but I understand it would be helpful if you could test with Jest :p I will leave this issue open but I am currently not able to dive into it. The fact that import is not recognized as a Keyword tells me the Babel config is not correct but I am not intimate with Jest so not sure about it. I do see a lot of issues / questions come up when I search for Jest and this error.

If you find a solution, please do let me know! I will do the same.

@Download
Copy link
Owner

Download commented Apr 24, 2018

Mmmmmmm wait.... I just realized something...

There is import and then there is dynamic import() (used by I18nline).

The import() keyword (with braces) acts like an async function. It is a proposal and not yet standardized. But Webpack (and other module bundlers) are already using it for code splitting purposes. I guess this is where the problem lies...

Does your project have a .babelrc file? If so, could you check if adding this plugin helps?
https://www.npmjs.com/package/babel-plugin-syntax-dynamic-import

I guess you have to add this when not using Webpack, but again I am not sure.

As an alternative you could try to replace the import() calls in the generated index file with require.ensure. This article describes that, but it is now recommended by the Webpack team to use import().

EDIT: references:
https://facebook.github.io/jest/docs/en/webpack.html
https://stackoverflow.com/questions/49260386/cant-test-a-function-with-a-dynamic-import-with-jest-and-babel-plugin-dynamic-i?rq=1
https://stackoverflow.com/questions/48537898/jest-test-case-gives-unexpected-token-in-dynamic-import-error?rq=1
https://stackoverflow.com/questions/49320450/jest-enzyme-syntaxerror-unexpected-token-import?noredirect=1&lq=1
jestjs/jest#2442
webpack/webpack#5123
https://stackoverflow.com/questions/48537898/jest-test-case-gives-unexpected-token-in-dynamic-import-error

@Download
Copy link
Owner

Download commented Apr 24, 2018

Ok, so... there is this book coming up that I have been working on that has a chapter about internationalization with Preact CLI. I can't share any of the book of course, but you can have a look at the example app that we published to Github for this book:
https://github.com/backstopmedia/preact-book-example

This repo has a branch i18n that has preact-i18nline configured. It might be helpful to have a look at this pull request. It contains all the changes I performed to add internationalization to the base app (the master branch). You should recognize the steps. When I run your command from src/tests in the i18n brand of this example app, it works as expected:

C:\ws\preact-book-example\src\tests>node ../../node_modules/jest/bin/jest.js
 PASS  .\Item.test.js
  <Item />
    √ should render a list item

 PASS  .\CommentItem.test.js
  <CommentItem />
    √ should render a comment item (16ms)
    √ should render a comment replies

 PASS  .\CommentsList.test.js
  <CommentsList />
    √ should render a list of comments

 PASS  .\header.test.js
  <Header />
    √ should render a title and nav

 PASS  .\HNList.test.js
  <HNList />
    √ should a HNList of articles (16ms)
    √ should have called fetch()

Test Suites: 5 passed, 5 total
Tests:       7 passed, 7 total
Snapshots:   6 passed, 6 total
Time:        5.897s
Ran all test suites.

I am now sorta committed to figure this thing out. Damn you, posing these baffling problems that my mind cannot let go of! What will come of my duties now? 😀

Anyway I will see if I can reproduce using your repro steps.

@Download
Copy link
Owner

Download commented Apr 24, 2018

Ok, so following your reproduction steps, I can indeed reproduce this issue. And I now think I understand why we did not encounter it in our example app.

In our example app, we import I18n directly from i18nline in the components (such as header) (this is also recommended in the docs BTW). We only import from '../i18n' in the App component. This is also where we handle the language change (I think this makes sense actually). This way, the whole import() mechanism is bypassed for Jest. It does mean that your translate button cannot be tested with Jest in this setup, because no translations are loaded yet. But afaik, Jest is for unit testing and this is more an integration test I guess so I'm not sure how much of an issue this is.

If you wanted to make this a pure unit test, you can mock the I18n.import function that is being added in the src/i18n/index.js file. I'm not sure how it works in Jest but I assume there is a way to run pre-test setup code? In that code you could implement I18n.import to just load some hardcoded strings. Or I guess this can be made to work by creating a .babelrc with some plugin thing to make Jest understand import() and deal with it (by using require.ensure below the surface).

I'm laying it to rest now. If you come up with a way to make Jest just understand import(), I think it would also be worth it to report it to the Preact CLI guys. Because I guess this is a problem with the default preact cli setup as well.

@yduman
Copy link

yduman commented Apr 25, 2018

Wow, first of all thank you for your dedication to this problem! I will try your proposals as soon as possible and will report my solutions. Thanks again!

@Download
Copy link
Owner

Download commented Apr 25, 2018

BTW, if you just import I18n from i18nline directly like in the book example app, you don't need to mock anything and can just test your components with Jest as you always would. It is just if you want to test the I18n.changeLocale stuff that you need to mock I18n.import or make Jest understand import(). Please do let me know and thank you for reporting your issue.

@yduman
Copy link

yduman commented Apr 26, 2018

Hello again,
I looked at the i18n branch of your preact-book-example repo and I changed my project accordingly the way you guys used i18n there. It works now how it should 😄

I think the problem was really, that I imported the I18n object from the generated index.js file instead of the i18nline package. Thanks again for your time and dedication to this problem! Much appreciated!

Cheers

@Download
Copy link
Owner

Hi @yduman
Thanks for reporting back and great to hear you solved your issue!

I think the problem was really, that I imported the I18n object from the generated index.js file instead of the i18nline package.

Yes, agreed.

My ramblings above about mocking only apply when you want to test the actual change locale functionality (your translate button). In that case, you need function I18n.changeLocale, which calls I18n.import, which is in the generated index file. So testing that would require some mocking.

If you finish your project I would be glad to hear from you! It would be really cool to add some projects using preact-i18nline to the README.

@yduman
Copy link

yduman commented Apr 26, 2018

I guess that I really can't share the project since we try to pitch Preact to very well known client. Compliance and stuff...

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

No branches or pull requests

3 participants