bluewings/pug-as-jsx-loader

Pug + react-boilerplate + i18n - custom tag

Closed this issue · 9 comments

Hi,

I trying to use i18n with pug, but I always receive this error:

Uncaught (in promise) TypeError: Cannot read property 'index' of undefined

This is my code:

import React from react;
import { FormattedMessage } from react-intl;
import messages from ./messages;

import template from ./index.pug;
import ../../assets/scss/main.scss;


export default class Home extends React.PureComponent { 
  render() {
    return template.call();
  }
}

My pug file:
div h1 FormattedMessage( __jsx='{...messages.index}')

Can you help me with this?

@fsabreu
When you call the transpiled template function, you must pass the variables used in the pug file.
In your case, you need to pass the variables FormattedMessage and messages.

export default class Home extends React.PureComponent { 
  render() {
    return template({
      messages,
      FormattedMessage,
    });
  }
}

// or

export default function Home (/* props */) {
  return template({
    messages,
    FormattedMessage,
  });
}

You can find the required variables in the pug-jsx file in the following way.


Add the transpiledFile option in webpack.config.js.

...
{
  test: /\.pug$/,
  use: [
    require.resolve('babel-loader'),
    {
      loader: require.resolve('pug-as-jsx-loader'),
      options: {
        transpiledFile: true,
      },
    },
  ],
},

It will create a example.pug.transpiled.jsx file. (this file is for checking the transpile results and is not related to program execution)

It is recommended to add this file type to the .gitignore file.

# transpiled pug-jsx file
*.transpiled.jsx

example.pug

div
  h1
    FormattedMessage(__jsx='{...messages.index}')

You can see the transpiled code and usage example. example.pug.transpiled.jsx

See using render function examples for more information.

import React from 'react';

export default function (params = {}) {
  const { messages, FormattedMessage } = params;
  return (
    <div>
      <h1>
        <FormattedMessage {...messages.index} />
      </h1>
    </div>
  );
}

//  /* USAGE EXAMPLE */
//  // Components
//  import FormattedMessage from '__modulePath__/FormattedMessage';
//
//  // jsx
//  import template from './WizardMask.pug';
//
//  class Report extends React.Component {
//
//    render() {
//      const {
//        messages,
//      } = this;
//
//      return template.call(this, {
//        // variables
//        messages,
//        // components
//        FormattedMessage,
//      });
//    }
//
//  }
//  /* // USAGE EXAMPLE */

Thank You!

Hello

Sorry to bother with that. But how can I do to put in a input value?

input.btn.btn-warning.btn-lg.btn-block(type="submit" value="HERE")

Thanks

@fsabreu

Do you mean the following?

check

And you can easily see the results on the page below.

https://bluewings.github.io/pug-as-jsx-loader/

Almost. I need to change to work. Like this:

FormattedMessage(__jsx='{...messages.button}') {(msg) => ( <input className="btn btn-warning btn-lg btn-block" type="submit" value={msg} /> )}

Thanks for the help

@fsabreu
And you do not need to pass FormattedMessage from .js to .pug.

resolveComponents option is available.

The import statement is added automatically when you use it. See this issue #1

// webpack.config.js
...
{
  test: /\.pug$/,
  use: [
    require.resolve('babel-loader'),
    {
      loader: require.resolve('pug-as-jsx-loader'),
      options: {
        resolveComponents: {
          FormattedMessage: 'i18n/FormattedMessage',
        },
      },
    },
  ],
},
...

Hi!
Can I do inline if in pug using FormattedMessage, like this?

button.btn.btn-outline-warning.btn-block(type="button" onClick="{this.handleChangePasswordClick.bind(this)}") {this.state.passState ? FormattedMessage(__jsx='{...messages.changePassword}') : FormattedMessage(__jsx='{...messages.save}')}

Tks

@gcuculi @fsabreu

You can use the @if attribute as shown below.

button.btn.btn-outline-warning.btn-block(type="button" onClick="{this.handleChangePasswordClick.bind(this)}")
  FormattedMessage(@if='this.state.passState', __jsx='{...messages.changePassword}')
  FormattedMessage(@unless='this.state.passState', __jsx='{...messages.save}')
import React from 'react';

export default function (params = {}) {
  const { messages, FormattedMessage } = params;
  return (
    <button
      className="btn btn-outline-warning btn-block"
      onClick={this.handleChangePasswordClick.bind(this)}
      type="button"
    >
      {(this.state.passState) && (
      <FormattedMessage {...messages.changePassword} />
      )}
      {!(this.state.passState) && (
      <FormattedMessage {...messages.save} />
      )}
    </button>
  );
}

or you can use it like this below, but I think the above solution is good to read and clear.

button.btn.btn-outline-warning.btn-block(type="button" onClick="{this.handleChangePasswordClick.bind(this)}")
  | {this.state.passState ?
  FormattedMessage(__jsx='{...messages.changePassword}')
  | :
  FormattedMessage(__jsx='{...messages.save}')
  | }
import React from 'react';

export default function (params = {}) {
  const { messages, FormattedMessage } = params;
  return (
    <button
      className="btn btn-outline-warning btn-block"
      onClick={this.handleChangePasswordClick.bind(this)}
      type="button"
    >
      {this.state.passState ?
      <FormattedMessage {...messages.changePassword} />
      :
      <FormattedMessage {...messages.save} />
      }
    </button>
  );
}

Thank you so much!
Works perfectly.