Django makemessages to get custom translatable strings - django

In my Django project I use Vue + vue-gettext for i18n.
To make translatable strings I have the following code in my my .vue files:
<translate>Hello %{name}</translate>
<a href="..." v-translate>Click here</a>
(using translate tags and v-translate attributes)
Is there a way to configure manage.py makemessages to parse this code as well? By default it does not look into .vue files or parse this i18n code format.

Basically I ended up having a Makfile - that extracts messages from vue files and then merges it with django
# On OSX the PATH variable isn't exported unless "SHELL" is also set, see: http://stackoverflow.com/a/25506676
SHELL = /bin/bash
NODE_BINDIR = ./node_modules/.bin
export PATH := $(NODE_BINDIR):$(PATH)
INPUT_DIR = static/js
# Where to write the files generated by this makefile.
OUTPUT_DIR = .
# Available locales for the app.
LOCALES = en nl fr
# Name of the generated .po files for each available locale.
LOCALE_FILES ?= $(patsubst %,$(OUTPUT_DIR)/locale/%/LC_MESSAGES/app.po,$(LOCALES))
GETTEXT_HTML_SOURCES = $(shell find $(INPUT_DIR) -name '*.vue' -o -name '*.html' 2> /dev/null)
GETTEXT_JS_SOURCES = $(shell find $(INPUT_DIR) -name '*.vue' -o -name '*.js')
# Makefile Targets
.PHONY: clean makemessages
clean:
rm -f /tmp/template.pot
makemessages: clean django_makemessages /tmp/template.pot
django_makemessages:
./manage.py makemessages $(patsubst %,-l %,$(LOCALES))
# Create a main .pot template, then generate .po files for each available language.
# Thanx to Systematic: https://github.com/Polyconseil/systematic/blob/866d5a/mk/main.mk#L167-L183
/tmp/template.pot: $(GETTEXT_HTML_SOURCES)
# `dir` is a Makefile built-in expansion function which extracts the directory-part of `$#`.
# `$#` is a Makefile automatic variable: the file name of the target of the rule.
# => `mkdir -p /tmp/`
mkdir -p $(dir $#)
which gettext-extract
# Extract gettext strings from templates files and create a POT dictionary template.
gettext-extract --attribute v-translate --quiet --output $# $(GETTEXT_HTML_SOURCES)
# Extract gettext strings from JavaScript files.
xgettext --language=JavaScript --keyword=npgettext:1c,2,3 \
--from-code=utf-8 --join-existing --no-wrap \
--package-name=$(shell node -e "console.log(require('./package.json').name);") \
--package-version=$(shell node -e "console.log(require('./package.json').version);") \
--output $# $(GETTEXT_JS_SOURCES)
# Generate .po files for each available language.
#for lang in $(LOCALES); do \
export PO_FILE=$(OUTPUT_DIR)/locale/$$lang/LC_MESSAGES/djangojs.po; \
echo "msgmerge --update $$PO_FILE $#"; \
mkdir -p $$(dirname $$PO_FILE); \
[ -f $$PO_FILE ] && msgmerge --lang=$$lang --update --backup=off $$PO_FILE $# || msginit --no-translator --locale=$$lang --input=$# --output-file=$$PO_FILE; \
msgattrib --no-wrap --no-obsolete -o $$PO_FILE $$PO_FILE; \
done;

I don't use vue-gettext since Django provides the JavaScriptCatalog view but I still faced the same issues with makemessages not picking up translation string in templates.
Using Django 4, Vue 3, and gettext 0.21 I made my own makemessages management command that overrides the Django's built-in one
from django.core.management.commands import makemessages
class Command(makemessages.Command):
"""
Overrides the default `makemessages` to add my own configuration & extend the command to recognize `interpolate` keyword in JS source files
"""
def handle(self, *args, **kwargs):
# Disable writing of the string's source file location in the generate po file
kwargs['no_location'] = True
# Ignore node_modules by default
kwargs['ignore_patterns'] = ['node_modules/*']
if kwargs['domain'] == 'djangojs':
# Set the default extensions
kwargs['extensions'] = kwargs['extensions'] or []
kwargs['extensions'].append('.js')
kwargs['extensions'].append('.vue')
self.xgettext_options.append('--keyword=interpolate')
# Set language to C so xgettext can pick up translations in Vue templates
self.xgettext_options.append('--language=C')
return super().handle(*args, **kwargs)
With default JavaScriptCatalog setup I have a js module that I import whenever I want to translate something
// Exports Django's `JavaScriptCatalog` functions dynamically
const djangoTranslationFns = [
'gettext',
'ngettext',
'get_format',
'gettext_noop',
'pgettext',
'npgettext',
'pluralidx',
];
const exports = {};
if (Object.keys(window).includes(djangoTranslationFns[0])) {
// If one of the functions are defined then it's safe to asumme they all are
djangoTranslationFns.forEach((fn) => { exports[fn] = window[fn]; });
// Override the interpolate function so it uses `gettext` by default
exports.interpolate = (fmt, obj, named) => window.interpolate(window.gettext(fmt), obj, named);
}
export default exports;
Then in the template
<script setup>
import i18n from '#/i18n';
</script>
<template>
<h1>{{ i18n.gettext("Welcome") }}</h1>
</template>

Related

How to customize folder name when compilemessages in website insternationalization

For website Internationalization when run this command
django-admin compilemessages -l de
it produce the .po file under the locale folder like
locale/de/LC_MESSAGES/django.po
I want to rename LC_MESSAGES
How can I do this ???
Please help me
You should add a code snippet to rename the directory, this is the hard way but unfortunately, I don't know a better one.
import os
basedir = 'locale/de/' # Or you should add something like C:/locale/de
newname = 'Your script'
os.rename(os.path.join(basedir, newname)

Sphinx documentation and autodoc-skip-member

I'm building my sphinx doc for a django project the following way:
sphinx-apidoc app -o docs/source/app --force
Now it includes all of the South migrations which I don't want to have in my documentation. I now tried to exclude them the following way:
conf.py:
def skip_migrations(app, what, name, obj, skip, options):
return skip or (what == 'module' and name.find('Migration') != -1)\
or str(obj).find('migrations') != -1
def setup(app):
app.connect('autodoc-skip-member', skip_migrations)
Now they aren't documented anymore, but are still listed under modules. How can I exclude them?
You may exclude the rst files created for the migrations by adding them to the exclude_pattern in your conf.py file:
exclude_patterns = ["**/*.migrations.rst",]
Just avoid generating the .rst files with sphinx-apidoc in the first place:
sphinx-apidoc app -o docs/source/app --force */migrations/*
Patterns added after the module name are understood as excluded paths.

Python scons building

Now I am studying an open source fluid simulation called pabalos. I have some problems building my own program that links against the library.
The library is built from source using scons.
The directory of the project is :
[fred#suck palabos-v1.1r0]$ls
codeblocks/ examples/ jlabos/ pythonic/ SConstruct utility/
COPYING externalLibraries/ lib/ scons/ src/
I will refer to this as the project root directory!
The project's official building documentation says:
The library Palabos makes use of an on-demand compilation process. The
code is compiled the first time it is used by an end-user application,
and then automatically re-used in future, until a new compilation is
needed due to a modification of the code or compilation options.
In the examples directory, there are some example code directories, such as :
[fred#suck palabos-v1.1r0]$ls examples/showCases/rectangularChannel3d/*
examples/showCases/rectangularChannel3d/Makefile
examples/showCases/rectangularChannel3d/rectangularChannel3D.cpp
The Makefile of the example is:
[fred#suck rectangularChannel3d]$cat Makefile
##########################################################################
## Makefile for the Palabos example program rectangularChannel3D.
##
## The present Makefile is a pure configuration file, in which
## you can select compilation options. Compilation dependencies
## are managed automatically through the Python library SConstruct.
##
## If you don't have Python, or if compilation doesn't work for other
## reasons, consult the Palabos user's guide for instructions on manual
## compilation.
##########################################################################
# USE: multiple arguments are separated by spaces.
# For example: projectFiles = file1.cpp file2.cpp
# optimFlags = -O -finline-functions
# Leading directory of the Palabos source code
palabosRoot = ../../..
# Name of source files in current directory to compile and link with Palabos
projectFiles = rectangularChannel3D.cpp
# Set optimization flags on/off
optimize = true
# Set debug mode and debug flags on/off
debug = false
# Set profiling flags on/off
profile = false
# Set MPI-parallel mode on/off (parallelism in cluster-like environment)
MPIparallel = true
# Set SMP-parallel mode on/off (shared-memory parallelism)
SMPparallel = false
# Decide whether to include calls to the POSIX API. On non-POSIX systems,
# including Windows, this flag must be false, unless a POSIX environment is
# emulated (such as with Cygwin).
usePOSIX = true
# Path to external libraries (other than Palabos)
libraryPaths =
# Path to inlude directories (other than Palabos)
includePaths =
# Dynamic and static libraries (other than Palabos)
libraries =
# Compiler to use without MPI parallelism
serialCXX = g++
# Compiler to use with MPI parallelism
parallelCXX = mpicxx
# General compiler flags (e.g. -Wall to turn on all warnings on g++)
compileFlags = -Wall -Wnon-virtual-dtor
# General linker flags (don't put library includes into this flag)
linkFlags =
# Compiler flags to use when optimization mode is on
optimFlags = -O3
# Compiler flags to use when debug mode is on
debugFlags = -g
# Compiler flags to use when profile mode is on
profileFlags = -pg
##########################################################################
# All code below this line is just about forwarding the options
# to SConstruct. It is recommended not to modify anything there.
##########################################################################
SCons = $(palabosRoot)/scons/scons.py -j 2 -f $(palabosRoot)/SConstruct
SConsArgs = palabosRoot=$(palabosRoot) \
projectFiles="$(projectFiles)" \
optimize=$(optimize) \
debug=$(debug) \
profile=$(profile) \
MPIparallel=$(MPIparallel) \
SMPparallel=$(SMPparallel) \
usePOSIX=$(usePOSIX) \
serialCXX=$(serialCXX) \
parallelCXX=$(parallelCXX) \
compileFlags="$(compileFlags)" \
linkFlags="$(linkFlags)" \
optimFlags="$(optimFlags)" \
debugFlags="$(debugFlags)" \
profileFlags="$(profileFlags)" \
libraryPaths="$(libraryPaths)" \
includePaths="$(includePaths)" \
libraries="$(libraries)"
compile:
python $(SCons) $(SConsArgs)
clean:
python $(SCons) -c $(SConsArgs)
/bin/rm -vf `find $(palabosRoot) -name '*~'`
I know this makefile will call scons, and SConstruct file is in the project root dir as I have shown.
The SContstruct file is :
[fred#suck palabos-v1.1r0]$cat SConstruct
###########################################################
# Configuration file for the compilation of Palabos code,
# using the SConstruct library.
# IT IS NOT RECOMMENDED TO MODIFY THIS FILE.
# Compilation should be personalized by adjusting the
# Makefile in the directory of the main source files.
# See Palabos examples for sample Makefiles.
###########################################################
import os
import sys
import glob
argdict = dict(ARGLIST)
# Read input parameters
palabosRoot = argdict['palabosRoot']
projectFiles = Split(argdict['projectFiles'])
optimize = argdict['optimize'].lower() == 'true'
debug = argdict['debug'].lower() == 'true'
profile = argdict['profile'].lower() == 'true'
MPIparallel = argdict['MPIparallel'].lower() == 'true'
SMPparallel = argdict['SMPparallel'].lower() == 'true'
usePOSIX = argdict['usePOSIX'].lower() == 'true'
serialCXX = argdict['serialCXX']
parallelCXX = argdict['parallelCXX']
compileFlags = Split(argdict['compileFlags'])
linkFlags = Split(argdict['linkFlags'])
optimFlags = Split(argdict['optimFlags'])
debugFlags = Split(argdict['debugFlags'])
profileFlags = Split(argdict['profileFlags'])
libraryPaths = Split(argdict['libraryPaths'])
includePaths = Split(argdict['includePaths'])
libraries = Split(argdict['libraries'])
# Read the optional input parameters
try:
dynamicLibrary = argdict['dynamicLibrary'].lower() == 'true'
except:
dynamicLibrary = False
try:
srcPaths = Split(argdict['srcPaths'])
except:
srcPaths = []
flags = compileFlags
allPaths = [palabosRoot+'/src'] + [palabosRoot+'/externalLibraries'] + includePaths
if optimize:
flags.append(optimFlags)
if debug:
flags.append(debugFlags)
flags.append('-DPLB_DEBUG')
if profile:
flags.append(profileFlags)
linkFlags.append(profileFlags)
if MPIparallel:
compiler = parallelCXX
flags.append('-DPLB_MPI_PARALLEL')
else:
compiler = serialCXX
if SMPparallel:
flags.append('-DPLB_SMP_PARALLEL')
if usePOSIX:
flags.append('-DPLB_USE_POSIX')
env = Environment ( ENV = os.environ,
CXX = compiler,
CXXFLAGS = flags,
LINKFLAGS = linkFlags,
CPPPATH = allPaths
)
if dynamicLibrary:
LibraryGen = env.SharedLibrary
else:
LibraryGen = env.Library
sourceFiles = []
for srcDir in glob.glob(palabosRoot+'/src/*'):
sourceFiles.extend(glob.glob(srcDir+'/*.cpp'))
for srcDir in srcPaths:
sourceFiles.extend(glob.glob(srcDir+'/*.cpp'))
sourceFiles.extend(glob.glob(palabosRoot+'/externalLibraries/tinyxml/*.cpp'));
if MPIparallel:
palabos_library = LibraryGen( target = palabosRoot+'/lib/plb_mpi',
source = sourceFiles )
else:
palabos_library = LibraryGen( target = palabosRoot+'/lib/plb',
source = sourceFiles )
local_objects = env.Object(source = projectFiles)
all_objects = local_objects + palabos_library
env.Program(all_objects, LIBS=libraries, LIBPATH=libraryPaths)
My problem is:
When I changed the source file rectangularChannel3D.cpp in the example dir,
and run make, the palabos library should not be rebuilt since I didn't change
the library project's source file (in the 'src' dir of the root dir) at all. But
actually the lib file "libplb.a" had been rebuilt!! So why?
I agree with Brady. Try contacting the project you're trying to build.
Alternatively, if you get no help from them, and/or really want to fix this yourself, SCons has a flag --debug=explain which will tell you why any object is being build/rebuilt.

Empty catalog when internationalizing JavaScript code

I'm trying to set up Internationalization of JavaScript code in my Django application.
My Django app has a locale subdirectory with a properly generated djangojs.po file. The package definition is as follows:
# urls.py
js_info_dict = {
'packages': ('my_project',),
}
./manage.py makemessages worked well as the .po file contains all the to-be-translated strings but no JavaScript string ever gets translated on the website and the catalog is always empty.
I also had some problems with. This is how it works for me:
Add this to yr root urls.py:
js_info_dict = { 'domain': 'djangojs',
'packages': ('YOUR_PROJECT_NAME',), }
urlpatterns = patterns('',
#enable using translation strings in javascript
#source: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#module-django.views.i18n
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
)
In JS files use:
var somevar = gettext('Text to translate');
To compile django translation files: In a shell/terminal run from the project root (where 'apps', 'settings', etc lie):
#for "normal django files" (.py, .html):
django-admin.py makemessages --locale=de
#for javascript files. source: http://stackoverflow.com/a/3571954/268125
django-admin.py makemessages -a -d djangojs --locale=de
#to compile the translation files to machine code
django-admin.py compilemessages --locale=de
i added my_project to INSTALLED APPS in settings.py and that seemed to do the trick

How do I localize js templates in Django

I've the problem, template for dynamic JS file is main.js located in TEMPLATE_DIRS. When I do ./manage.py makemessages -a all messages {% trans "MSG" %} are fetched but not from main.js template.
Of course I can rename main.js to main.js.html, is any pretty way?
./manage.py makemessages -d djangojs — dont help.
You can specify extensions in makemessages command (see django docs):
django-admin.py makemessages -d djangojs -l de -e js -e html,txt