Extracting Javascript gettext messages using Babel CLI extractor - javascript

It is stated here that Babel can extract gettext messages for Python and Javascript files.
Babel comes with a few builtin extractors: python (which extracts
messages from Python source files), javascript, and ignore (which
extracts nothing).
The command line extractor is documented here - but with no examples on usage.
Also in the same pointer above, there is some mention of a config file to be used with extraction, but not much expanded on.
When I run the basic command for the extractor on a dir with js files, I get only the .PO header generated but no messages.
$ pybabel extract /path/to/js-dir
# Translations template for PROJECT.
# Copyright (C) 2012 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL#ADDRESS>, 2012.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL#ADDRESS\n"
"POT-Creation-Date: 2012-04-22 19:39+1000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL#ADDRESS>\n"
"Language-Team: LANGUAGE <LL#li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 0.9.6\n"
$
Here is a sample segment from a js file I'm trying to extract messages for:
else if(data.status == "1"){
var follow_html = gettext('Follow');
object.attr("class", 'button follow');
object.html(follow_html);
var fav = getFavoriteNumber();
fav.removeClass("my-favorite-number");
if(data.count === 0){
data.count = '';
fav.text('');
}else{
var fmts = ngettext('%s follower', '%s followers', data.count);
fav.text(interpolate(fmts, [data.count]));
}
}
I would appreciate it if someone can provide exact CLI options and config settings to make the extraction work, or a pointer to such.

Create a file (babel.cfg) with the following content:
[javascript:*.js]
encoding = utf-8
Then, do:
pybabel extract -F babel.cfg /path/to/js-dir
That should be enough for you to have some message strings.
BTW, you can consult the help for the extract command by doing:
pybabel extract --help

I had a similar issue and was able to get around it by disabling default keywords with babel.
pybabel extract -k __ -F babel.cfg --no-default-keywords /path/to/js-dir
You must specify at least one keyword in the command when you disable the defaults (-k [keyword]). I chose -k __ because "__" was a pattern I was looking for.
Just use this command and replace the "__" after -k with one from your babel.cfg file.
Edit: this allows you to use your own keywords rather than gettext()

You can create an object in as flask global and translate it with gettext
g.i18n = {
'Casa' : lazy_gettext('Home'),
'Auto' : lazy_gettext('Car'),
'Persona' : lazy_gettext('Person')
}
Then add it as a variable
<script>
var i18n = {{ g.i18n | tojson }}
</script>
and use it in JS:
var labelTranslate = {
Casa: i18n.Casa,
Persona: i18n.Persona,
Auto: i18n.Auto
};

You can actually use gettext directly in Javascript.
See: jsgettext. It allows you to use the standard *gettext functions, including the one using contexts and/or plural forms.
It can read PO/MO files or you can import custom made JSON files instead.
See this file of this project for a complete example.

Related

What is the gettext command's language for jQuery in poedit?

I am making a pot file where I want the file to scan for gettext keywords in a JS jQuery file. It scans the php perfectly, but the .js file seems not be working. I am wondering if I have actually the extractor setup correct for the command's language. This is what I have:
Language: JS
List of extensions: *.js
Command: ‪xgettext --language=C --force-po -o %o %C %K %F
It scans the file, but nothing is added. What is the language for jQuery?
To give more information:
This is an example of the JS file:
jQuery(document).ready(function() {
if(location.href.indexOf('/<?php esc_html_e('url_page_discount', 'custom-translation-strings' ?>/') > -1){ //rewards
jQuery('.rs_custom_fblike_button').attr('value', '<?php esc_attr_e('I Like', 'custom-translation-strings' ?>');
if (jQuery('#menu-item-10159').length){
jQuery('#rs_friend_subject').attr('value', '<?php esc_attr_e('Discount for an interesting store!', 'custom-translation-strings' ?>');
}
}
});
I have covered the esc_attr_e() in the sources keywords:
I am wondering if I have actually the extractor setup correct for the command's language
You don't. The very fact that you're even configuring extraction suggests that you're either using a very old version of Poedit or you're adding custom configurations. In either case, don't: update to the latest, delete or disable all your custom extractors, and let Poedit do its thing with defaults.
Command: ‪xgettext —language=C --force-po -o %o %C %K %F
You're asking Poedit to treat JavaScript files as being written in C. The results predictably follow the GIGO principle.
This is an example of the JS file:
You're putting (even PHP!) code into string literals. That's a) not going to work and b) cannot have any translatable strings extracted from.

How to use different syntax for same file extension on Sublime Text? (JS/JSX)

With Sublime Text, is it possible to use different syntax for a same file extension depending on the currently opened project ?
Example :
Project A : file.js contains classic Javascript
Project B : file.js contains JSX
How can I obtain JavaScript syntax for project A and Babel syntax for Project B?
Just for background (which you likely already know), Sublime Text applies a syntax via the extension of the file, and overriding that requires you to use View > Syntax > Open all with current extension as... from the menu. This creates a syntax specific override which appears in a specific file name and is thus not directly overrideable on a per project basis.
That said, it is possible to swap the syntax on your own (e.g. via the command palette) which opens the possibility of a plugin being able to do this for you. There may be an existing plugin that does this in PackageControl, but for reference purposes, here is an example based on something I'm using for a similar purpose.
The following assumes that you're using the Babel plugin to get your syntax highlighting, since you mention Babel. This would need to be modified if this is not the package you're using. This could also be modified to similarly do a swap for a different type of file if desired.
To use this, select Tools > Developer > New Plugin from the menu and replace the entire contents of the sample file with the code below, and then save it as a python file in the directory that Sublime suggests (which should be in Packages\User). I named mine js_syntax_swap.py, but the name doesn't matter as long as the extension is .py:
import sublime, sublime_plugin
# Standard Sublime JavaScript syntax file is:
# 'Packages/JavaScript/JavaScript.sublime-syntax'
#
# The Babel package syntax is:
# 'Packages/Babel/JavaScript (Babel).sublime-syntax'
class JavaScriptSyntaxSwap (sublime_plugin.EventListener):
def modify_syntax (self, view):
if view.window () == None:
return
swapSyntax = view.settings ().get ('using_babel_js', False)
curSyntax = view.settings ().get ('syntax')
variables = view.window ().extract_variables ()
extension = variables['file_extension']
if swapSyntax is True and extension == 'js' and "Babel" not in curSyntax:
view.set_syntax_file ('Packages/Babel/JavaScript (Babel).sublime-syntax')
def on_load (self, view):
self.modify_syntax (view)
def on_post_save (self, view):
self.modify_syntax (view)
With this in place, if you choose Project > Edit Project from the menu, you can include a using_babel_js setting to enable the plugin for JavaScript files in that project. An example might be:
{
"folders":
[
{
"path": "."
}
],
"settings":
{
"using_babel_js": true
}
}
What this is doing is checking every time you load or save a file to see if it should swap the syntax from the default to the Babel JSX syntax, which it does only for files with the extension .js that are not already using Babel as the syntax.

syntax validator for a less file

I need a validator for a less file. I need to validate a single less file, at only syntax level.
I can't get the validator to follow the dependencies or detect if a mixin is declared or not. That is my real problem.
I have found a lot of less processors which fail because the file has dependencies that i can't provide in this point of the process.
npm package would be perfect.
Finally, I decided to use antlr4
Steps:
install antlr in the computer or add to the deployment process
get the grammar for your language (less is already done)
get the npm package to process the grammar
Use it in your app
The configuration is:
$ cd /usr/local/lib
$ sudo curl -O http://www.antlr.org/download/antlr-4.5-complete.jar
$ export CLASSPATH=".:/usr/local/lib/antlr-4.5-complete.jar:$CLASSPATH"
$ alias antlr4='java -jar /usr/local/lib/antlr-4.5-complete.jar'
$ alias grun='java org.antlr.v4.runtime.misc.TestRig
This info is directly from the web page.
Now you can get the grammar from https://github.com/antlr/grammars-v4
At this point you can generate the javascript version of your grammar
In my case, I created a directory, I downloaded the files and coded all my tests inside:
antlr4 -Dlanguage=JavaScript LessParser.g4
antlr4 -Dlanguage=JavaScript LessLexer.g4
This process generates a javascript file that you will use, but you need the antlr lib for use this files in your node program.
npm link antlr4
Ant now starts to code:
var antlr4 = require('antlr4/index');
var MyGrammarLexer = require('./LessLexer.js');
var MyGrammarParser = require('./LessParser.js');
var input = "html{ .hey(); color: #light-blue; background:#333}";
var chars = new antlr4.InputStream(input);
var lexer = new MyGrammarLexer.LessLexer(chars);
var tokens = new antlr4.CommonTokenStream(lexer);
var parser = new MyGrammarParser.LessParser(tokens);
parser.buildParseTrees = true;
var ErrorListener = antlr4.error.ErrorListener;
function CustomErrorListener() {
ErrorListener.call(this);
return this;
}
CustomErrorListener.prototype = Object.create(ErrorListener.prototype);
CustomErrorListener.prototype.constructor = CustomErrorListener;
CustomErrorListener.prototype.syntaxError = function(recognizer, offendingSymbol, line, column, msg, e) {
throw ('throw a simple exception');
};
parser.addErrorListener(new CustomErrorListener());
try{
var tree = parser.stylesheet();
} catch (e){
console.log('I catch you!!!')
}
The important parts in this code are the function lessLexer, lessParser, and parser.stylesheet(); This are different per grammar. The last one is difficult to know, but it is the point in the grammar that you want to validate. In my case, I get the file LessParser.g4, and you have the different node in the grammar in the definition:
parser grammar LessParser;
options { tokenVocab=LessLexer; }
stylesheet
: statement*
;
statement
: importDeclaration
| ruleset
| variableDeclaration ';'
| mixinDefinition
;
variableName
: AT variableName
| AT Identifier
;
commandStatement
: (expression+) mathStatement?
;
mathCharacter
: TIMES | PLUS | DIV | MINUS | PERC
;
In this case, you can validate the string like a stylesheet, statement, variableName ...
The last interesting point is the Error Validation, I use it to stop the validation in the first error, my case is very simple, but you can improve this point

Can I write scripts for hubot in Javascript?

Hubot is Github's chatroom robot. It's a great tool, except that no one at our company wants to write in Coffeescript....but it appears that we can't write scripts for Hubot in plain old Javascript.
Is this true? Is there something I'm missing here? Coffeescript is "just javascript" but I can't use Javascript with it?
EDIT
I was making 2 absurdly simple mistakes:
- I copied the CoffeeScript comment syntax into my JS file
- I had the script under the hubot-scripts node_module, instead of just under the /scripts/ directory in the main project.
Works perfectly now.
Yes, you can write your hubot scripts in pure JavaScript. Following is a simple hubot script written in pure JavaScript and put under the /scripts/ directory of my customized hubot:
// Description:
// holiday detector script
//
// Dependencies:
// None
//
// Configuration:
// None
//
// Commands:
// hubot is it weekend ? - returns whether is it weekend or not
// hubot is it holiday ? - returns whether is it holiday or not
module.exports = function(robot) {
robot.respond(/is it (weekend|holiday)\s?\?/i, function(msg){
var today = new Date();
msg.reply(today.getDay() === 0 || today.getDay() === 6 ? "YES" : "NO");
});
}
CoffeeScript is compiled into JavaScript, but it's not a superset of JavaScript, so JavaScript code isn't necessarily valid CoffeeScript code.
Nevertheless, after looking at the source, it looks like Hubot can accept both:
# Public: Loads a file in path.
#
# path - A String path on the filesystem.
# file - A String filename in path on the filesystem.
#
# Returns nothing.
loadFile: (path, file) ->
ext = Path.extname file
full = Path.join path, Path.basename(file, ext)
if ext is '.coffee' or ext is '.js'
try
require(full) #
#parseHelp "#{path}/#{file}"
catch error
#logger.error "Unable to load #{full}: #{error.stack}"
process.exit(1)
This method is called by loadHubotScripts.

Django's support for translations in Javascript files

I read and followed the instructions in here, but can't seem to see the string in the javascript in the po file.
structure of my project is:
cb/
cb_app
cb
static_files
templates
First I copied these into my url.py:
js_info_dict = {
'packages': ('cb_app',),
}
urlpatterns = patterns('',
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
)
Then I added this script to my html:
<script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script>
The actual script where I would like to get the translation, is as simple as that:
$(document).ready(function () {
$('#id_sales_item').chosen({no_results_text: gettext('No results match')});
});
...and is utilized in the same html.
So is there anything more I need to do?
All I did then was to run the line below both from cb/cb and from cb/cb_app.
django-admin.py makemessages -l en_GB
But still no sign of 'No results match' in either cb/cb/locale nor in cb/cb_app/locale
Any tips?
I have finally found the problem.
The documentation suggests creating the messages once from the Django project and once from Django app. That way you end up with two locale directory. And in neither of those would the javascript translations be picked up anyway. This is quite a mess.
The cleanest solution I have found is to go to settings.py and insert this line (see also my project hierarchy above):
LOCALE_PATHS = ( '/home/kave/projects/cb/locale',)
Then create a directory called locale in the project-root-directory (see the path above)
Don't forget applying the entries into url.py and html as well (see above).
Finally now that the local's are unified into one place, go to project-root-directory: /home/kave/projects/cb and run these two commands:
django-admin.py makemessages -l en_GB
django-admin.py makemessages -d djangojs -l en_GB
The first command get the translation texts from both project and app subfolders.
The second gets the javascript translation into a second po file.
Thats it.

Categories