Git Product home page Git Product logo

gettext-loader's Introduction

gettext-loader

Build Status

A Webpack loader that compiles Gettext PO files from source code.

Installation

npm install --production gettext-loader

Getting Started

To use gettext-loader you will need a gettext.config.js file in your root directory. This config file contains the header for your PO file as well as the localization methods used in your code.

module.exports = {
  methods: ['__', 'translate'],
  output: 'i18n/en.po',
  header: {
    'Project-Id-Version': '1233',
    'Report-Msgid-Bugs-To':'Jonathan Huang',
    'Last-Translator': 'Jonathan Huang',
    'Language-Team': 'Squad Everywhere',
    'Language': 'en',
    'Plural-Forms': 'nplurals=2; plural=(n != 1);',
    'MIME-Version': '1.0',
    'Content-Type': 'text/plain; charset=UTF-8',
    'Content-Transfer-Encoding': '8bit'
  }
}

You can also specify a literal header prefix to include in the file, for comments or other things.

module.exports = {
  header_prefix: '# this is my po file\nmsgid ""\nmsgstr ""'

Since 'gettext-loader' only parses Javascript (including ES6 and JSX), place it after loaders that transform some source to JS code.

module: {
  loaders: [
    { test: /\.jst/, loaders: ['gettext-loader', 'dot-loader'] },
    { test: /\.jsx?$/, loaders: ['babel', 'gettext-loader'] },
    { test: /\.coffee/, loaders: ['gettext-loader', 'coffee-loader'] }
  ]

gettext-loader does not modify your source code. It only outputs a PO file by parsing your JS source code.

Running Examples

npm install --peer
npm run examples

PO File Generation

gettext-loader parses your source code:

//example.jsx
import React from 'react';
import {__} from 'i18n';

const translation = __('evening star');
const plural = __('I saw the morning star %d day ago')

class Example extends React.Component {
  render(){
    return (
      <div className='container'>
        <div className='top'>
          <p>{this.props.text}</p>
          <p></p>
          <p>{__('pegasus')}</p>
        </div>
        <form>
          <input type='text' placeholder={__('morning star')}/>
        </form>
      </div>
    )
  }
}

And generates a .po file from it:

"Project-Id-Version : 1233"
"Report-Msgid-Bugs-To : Jonathan Huang"
"Last-Translator : Jonathan Huang"
"Language-Team : Squad Everywhere"
"Language : en"
"Plural-Forms : nplurals=2; plural=(n != 1);"
"MIME-Version : 1.0"
"Content-Type : text/plain; charset=UTF-8"
"Content-Transfer-Encoding : 8bit"

#: assets/jsx/example.jsx 5:23
msgid "evening star"
msgtr ""

#: assets/jsx/example.jsx 6:17
msgid "I saw the morning star %d day ago"
msgtr[0] ""
msgtr[1] ""

#: assets/jsx/example.jsx 15:14
msgid "pegasus"
msgtr ""

#: assets/jsx/example.jsx 18:42
msgid "moring star"
msgtr ""

Multiple PO File Output

If you want to use code splitting with your po files, you can configure gettext-loader to use the source file's name as part of its output file.

module.exports = {
  output: 'i18n/[filename]_en.po'
}

[filename] will be replaced with the filename where translations are found.

gettext-loader's People

Contributors

jampy avatar lucbelliveau avatar mrblueblue avatar nevon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

gettext-loader's Issues

msgtr or msgstr?

Hi, it seems there is a typo in emitted PO file, you were probably intended to use msgstr token instead of msgtr, am I wrong?

Translation Context

Hello!

I'm interested in using this project, but we have a requirement for msgctxt values. I believe this is not supported by this project in its current state, but please correct me if I'm wrong. What are the chances of me writing and landing a PR to this project over the next few weeks? Are maintainers available to assist/approve?

Thanks

process.env.PWD undefined on windows

Hello,

The process.env.PWD is used at least 3 times in this project. On my work machine (Windows 7, node v6) this variable is undefined and cause an error with webpack (Module build failed. Type Error: Path must be a string. Received undefined from src/utils/buildMessageBlocks.js#L21).

I think the way to go is to use process.cwd() which will always return a value although not the same thing as PWD.

Here is my quickfix at the top of my webpack.config.json waiting for a fix for those interested

if (!process.env.PWD) {
  process.env.PWD = process.cwd();
}

Argument with operators errors out

A gettext function with an operator throws an error. So one cannot do this:

__('hello' +'how are you')
ERROR in ./app/scripts/presenters/presenter.coffee
Module build failed: TypeError: undefined does not have a method named "split"
  at /Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:7137:19
  at /Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:290:35
  at /Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:46:27
  at /Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:384:35
  at f1 (/Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:156:27)
  at XWrap.formatMessageBlock [as f] (/Users/jhuang/webapp/node_modules/gettext-loader/dist/utils/buildMessageBlocks.js:40:34)
  at XWrap.@@transducer/step (/Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:665:25)
  at _arrayReduce (/Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:4025:46)
  at _reduce (/Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:4055:24)
  at /Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:227:28
  at f1 (/Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:156:27)
  at /Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:384:22
  at f1 (/Users/jhuang/webapp/node_modules/ramda/dist/ramda.js:156:27)
  at Object.module.exports (/Users/jhuang/webapp/node_modules/gettext-loader/dist/index.js:77:16)
 @ ./app/scripts/modules/menu/menu.coffee 15:12-43

IIFE in JSX errors outs

ERROR in ./app/scripts/react-app/pages/repost-form/RepostFormPage.jsx
Module build failed: Error: Line 72: Unexpected token (
  at throwError (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:2819:21)
  at throwUnexpected (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:2881:9)
  at expect (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:2890:13)
  at parseJSXExpressionContainer (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:7078:9)
  at parseJSXChild (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:7127:21)
  at parseJSXElement (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:7206:31)
  at parsePrimaryExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3590:20)
  at parseLeftHandSideExpressionAllowCall (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3683:61)
  at parsePostfixExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3723:20)
  at parseUnaryExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3790:16)
  at parseBinaryExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3880:16)
  at parseConditionalExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3940:16)
  at parseAssignmentExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:4193:16)
  at parseExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:4250:16)
  at parseGroupExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3482:16)
  at parsePrimaryExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3575:20)
  at parseLeftHandSideExpressionAllowCall (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3683:61)
  at parsePostfixExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3723:20)
  at parseUnaryExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3790:16)
  at parseBinaryExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3880:16)
  at parseConditionalExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3940:16)
  at parseAssignmentExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:4193:16)
  at parseExpression (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:4250:16)
  at parseReturnStatement (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:5464:28)
  at parseStatement (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:5690:24)
  at parseSourceElement (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:6454:24)
  at parseFunctionSourceElements (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:5791:29)
  at parseConciseBody (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:5738:20)
  at parsePropertyFunction (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3096:16)
  at parsePropertyMethodFunction (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:3131:18)
  at parseMethodDefinition (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:6213:13)
  at parseClassElement (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:6270:36)
  at parseClassBody (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:6291:28)
  at parseClassDeclaration (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:6424:13)
  at parseStatement (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:5686:24)
  at parseSourceElement (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:6454:24)
  at parseExportDeclaration (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:4950:37)
  at parseSourceElement (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:6444:24)
  at parseProgramElement (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:6502:16)
  at parseProgramElements (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:6534:29)
  at parseProgram (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:6547:16)
  at Object.parse (/Users/jhuang/webapp/node_modules/esprima-fb/esprima.js:7724:23)
  at parseECMA (/Users/jhuang/webapp/node_modules/gettext-loader/dist/utils/parseECMA.js:17:55)
  at Object.module.exports (/Users/jhuang/webapp/node_modules/gettext-loader/dist/index.js:49:34)
 @ ./app/scripts/react-app/pages/repost-form/index.jsx 33:22-49

Unmet pere dependencies

I'm getting this on install:

npm ERR! peer dep missing: react@^0.14.3, required by [email protected]
npm ERR! peer dep missing: react@^0.13.3, required by [email protected]

Any advice on how I can fix this? I tried installing these, both locally and globally, did not work.

Handle pluralization better

If you take a look at the standard gettext method calls, you have more than one key in one method call, in the case of pluralization. For example:

i18n.ngettext('apple', 'apples', num)

gettext-loader would only pick up on 'apple'.

Even if we add %d to the strings, it will still only care about the first argument, so while I would like to get an entry like:

msgid "%d apple"
msgid_plural "%d apples"
msgstr[0] ""
msgstr[1] ""

I will just get:

msgid "%d apple"
msgstr[0] ""
msgstr[1] ""

I'm not sure how to work around this, but it seems to me that it would be a decent start to differentiate between function calls for singular translation and pluralized translations, and in the case of pluralized translations calls, record both the first and the second argument.

Something like this:

exports default {
  gettext: key => {
    // ... translate
  },
  gettextn: (singular, plural, num) => {
    // ... translate
  }
}

With this config:

export default {
  methods: {
    singular: ['gettext'],
    plural: ['gettextn']
  }
}
import {gettext, gettextn} from 'i18n'

gettext('Foo bar')

gettextn('One child', '%d children', 3)

Would result in:

msgid "Foo bar"
msgstr ""

msgid "A child"
msgid_plural "%d children"
msgstr[0] ""
msgstr[1] ""

questions for .po file generation

hi, when I run webpack, I see an undefined.po file gets generated at the root of my project.

  • the contents of the .po file look like
    • "0 : [object Object]"

this is what the contents of my gettext.config.js looks like:

module.exports = {
  methods: ['$translate', 't'],
  header: [{
    'Project-Id-Version': 'PROJECT VERSION',
    'Report-Msgid-Bugs-To': 'EMAIL@ADDRESS',
    'Last-Translator': 'FULL NAME <EMAIL@ADDRESS>',
    'Language': 'es',
    'Language-Team': 'es <[email protected]>',
    'Plural-Forms': 'nplurals=2; plural=(n != 1)',
    'MIME-Version': '1.0',
    'Content-Type': 'text/plain; charset=utf-8',
    'Content-Transfer-Encoding': '8bit'
    }]
};

I'm not clear if I'm setting the methods property correctly. I'm trying to use the i18n.t() function for translations. thanks.

  • is root the default location where .po files will get built and how could I change that?
  • can I build multiple .po files at once?
  • how should I set the .po file name

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.