How to Internationalize Sphinx (i18n) - internationalization

From the defaults following an execution of sphinx-quickstart, how do I get language-specific directories like what's used by Read The Docs?
I'm starting a new Sphinx documentation site that's hosted by GitHub Pages, built with GitHub Actions, and using the Read The Docs theme. Basically I'm trying to re-create Read The Docs but without ads or server-side search.
I won't be able to actually translate anything for a long time, but I do want to make sure that my new project is ready to be translated at a later time. Most specifically, I want to make sure that permalinks to my documentation will not change after I add translations. To that end, I'd like to make my documentation URL include the language in the URL (/en/stable/), for example:
https://docs.readthedocs.io/en/stable/
I followed the Sphinx Guide to Internationalization and set the language and locale_dirs variables in conf.py:
language = 'en'
locale_dirs = ['locale/']
gettext_compact = True
Unfortunately, after the changes above, make html and make -e SPHINXOPTS="-D language='en'" html still produce files without the en subdirectory
user#host:~/docs$ tree -L 2 _build
_build
├── doctrees
│   ├── environment.pickle
│   └── index.doctree
└── html
├── genindex.html
├── index.html
├── objects.inv
├── search.html
├── searchindex.js
├── _sources
└── _static
Am I missing something or is the documentation missing something? How do I setup a fresh Sphinx install with the defaults to build to language-specific html with make?

The undocumented truth is that sphinx doesn't do this. In fact, sphinx i18n functionality stops-short of a workflow for building all your language-specific directories. It's implicit that you have to design & wrap sphinx-build with your own scripts to set this up.
To translate your sphinx reST files to another language, you don't have to update your '.rst' files themselves. Sphinx already understands what a block of text looks like, and it can divide-up heading strings, captions, double-newline-separated paragraphs, etc into unique "source strings" (msgid), and put them into '.pot' source-language files and '.po' destination-language files.
First, run make gettext from the 'docs/' directory. This tells sphinx to parse your reST files and automatically find a bunch of strings-to-be-translated and give them a unique msgid.
user#host:~/rtd-github-pages$ cd docs/
user#host:~/rtd-github-pages/docs$ ls
autodoc.rst buildDocs.sh conf.py.orig locales Makefile
_build conf.py index.rst make.bat _static
user#host:~/rtd-github-pages/docs$
user#host:~/rtd-github-pages/docs$ make gettext
Running Sphinx v1.8.4
making output directory...
building [gettext]: targets for 0 template files
building [gettext]: targets for 2 source files that are out of date
updating environment: 2 added, 0 changed, 0 removed
Hello Worldrces... [ 50%] autodoc
reading sources... [100%] index
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [100%] index
writing message catalogs... [100%] index
build succeeded.
The message catalogs are in _build/gettext.
user#host:~/rtd-github-pages/docs$
The above execution should create the following files
user#host:~/rtd-github-pages/docs$ ls _build/gettext/
autodoc.pot index.pot
user#host:~/rtd-github-pages/docs$
Here's a snippet from '_build/gettext/index.pot' showing two strings on our documentation's main page that we'll translate from English to Spanish.
user#host:~/rtd-github-pages/docs$ grep -m2 -A2 .rst _build/gettext/index.pot
#: ../../index.rst:7
msgid "Welcome to helloWorld's documentation!"
msgstr ""
--
#: ../../index.rst:9
msgid "Contents:"
msgstr ""
user#host:~/rtd-github-pages/docs$
Next, let's tell sphinx to prepare some Spanish destination-language '.po' files from our above-generated source-lananguage '.pot' files.
Before proceeding with this step, you'll need to install sphinx-intl and the python Stemmer module. If you're using a Debian-based distro, you can do so with the following command.
sudo apt-get install -y sphinx-intl python3-stemmer
Execute the following command to prepare our Spanish-specific translation files.
user#host:~/rtd-github-pages/docs$ sphinx-intl update -p _build/gettext -l es
Create: locales/es/LC_MESSAGES/index.po
Create: locales/es/LC_MESSAGES/autodoc.po
user#host:~/rtd-github-pages/docs$
The above execution created two '.po' files: one for each of our '.pot' source-language files, which correlate directly to each of our two '.rst' files (index.rst and autodoc.rst). Perfect.
If we grep the new Spanish-specific 'docs/locales/es/LC_MESSAGES/index.po' file, we see it has the same contents as the source '.pot' file.
user#host:~/rtd-github-pages/docs$ grep -m2 -A2 .rst locales/es/LC_MESSAGES/index.po
#: ../../index.rst:7
msgid "Welcome to helloWorld's documentation!"
msgstr ""
--
#: ../../index.rst:9
msgid "Contents:"
msgstr ""
user#host:~/rtd-github-pages/docs$
These language-specific '.po' files are where we actually do the translating. If you're a large project, then you'd probably want to use a special program or service to translate these files. But, for clarity, we'll just edit the files directly.
user#host:~/rtd-github-pages/docs$ perl -pi -0e "s^(msgid \"Welcome to helloWorld's documentation\!\"\n)msgstr \"\"^\1msgstr \"¡Bienvenido a la documentación de helloWorld\!\"^" locales/es/LC_MESSAGES/index.po
user#host:~/rtd-github-pages/docs$ perl -pi -0e "s^(msgid \"Contents:\"\n)msgstr \"\"^\1msgstr \"Contenidos:\"^" locales/es/LC_MESSAGES/index.po
user#host:~/rtd-github-pages/docs$
user#host:~/rtd-github-pages/docs$ grep -m2 -A2 .rst locales/es/LC_MESSAGES/index.po
#: ../../index.rst:7
msgid "Welcome to helloWorld's documentation!"
msgstr "¡Bienvenido a la documentación de helloWorld!"
--
#: ../../index.rst:9
msgid "Contents:"
msgstr "Contenidos"
user#host:~/rtd-github-pages/docs$
As you can see, the above execution filled-in the contents of msgstr "" with the Spanish translation of the corresponding msgid line above it in the original (English) language.
Now let's build two versions of our html static content: [1] in English and [2] in Spanish.
user#host:~/rtd-github-pages/docs$ sphinx-build -b html . _build/html/en -D language='en'
Running Sphinx v1.8.4
loading translations [en]... done
making output directory...
building [mo]: targets for 0 po files that are out of date
building : targets for 2 source files that are out of date
updating environment: 2 added, 0 changed, 0 removed
Hello Worldrces... [ 50%] autodoc
reading sources... [100%] index
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [100%] index
generating indices... genindex py-modindex
highlighting module code... [100%] helloWorld
writing additional pages... search
copying static files... done
copying extra files... done
dumping search index in English (code: en) ... done
dumping object inventory... done
build succeeded.
The HTML pages are in _build/html/en.
user#host:~/rtd-github-pages/docs$
user#host:~/rtd-github-pages/docs$ sphinx-build -b html . _build/html/es -D language='es'
Running Sphinx v1.8.4
loading translations [es]... done
making output directory...
building [mo]: targets for 1 po files that are out of date
writing output... [100%] locales/es/LC_MESSAGES/index.mo
building : targets for 2 source files that are out of date
updating environment: 2 added, 0 changed, 0 removed
Hello Worldrces... [ 50%] autodoc
reading sources... [100%] index
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [100%] index
generating indices... genindex py-modindex
highlighting module code... [100%] helloWorld
writing additional pages... search
copying static files... done
copying extra files... done
dumping search index in Spanish (code: es) ... done
dumping object inventory... done
build succeeded.
The HTML pages are in _build/html/es.
user#host:~/rtd-github-pages/docs$
user#host:~/rtd-github-pages/docs$ firefox _build/html/en/index.html _build/html/es/index.html &
[1] 12134
user#host:~/rtd-github-pages/docs$
The firefox command in the above execution should open your browser with two tabs: (1) in English and (2) in Spanish.
For more information, see this article on how to setup internationalization in Sphinx.

Related

Makefile - pdf generation using LaTeX

I wrote a simple makefile to generate pdf using latex and I succeeded.
However, There are 2 point that irritates me:
when I run make the output PDF is in the same folder where the makefile is written and I want to change that
I want to copy the pdf file generated to another file with another name but I don't know how to do that
Here is a snippet of my code:
# Generating the file
$(FILE).pdf: $(IMAGES) $(PACKAGES) $(COMMON_TEX_SOURCES) $(FILE_TEX_SOURCES) $(FILE_IMAGES)
latexmk -lualatex $(FILE)
##############################################################################
#rule to generate file
file: $(FILE).pdf
Your help is appreciated
To make the target go into a another folder, change the target path:
some/dir/$(FILE).pdf: $(IMAGES) ...
To copy the file from one place to another:
some/other/dir/$(FILE).pdf: some/dir/$(FILE).pdf
cp $< $#

Makefile to process a folder's contents

I have a folder with some markdown files I want to process using pandoc and output them into another folder for a Jekyll site. I am attempting to use the following Makefile:
MARKDOWN = $(wildcard *.md)
jekyll-build : _posts/$(MARKDOWN)
bundle exec jekyll build
_posts/%.md : source/%.md
pandoc -s -t markdown-citations -o $# $<
However, instead of looking for the contents of the _posts folder, make is looking for any *.md files in the current working directory (where I have an index.md file), then complains it can't find _posts/index.md. From this question I gather it's the expected behavior of pattern rules, so my question is: how do I get make to look for all existing files in the source folder and run the recipe on each one of them?
MARKDOWN = $(wildcard source/*.md)
POSTS := $(patsubst source/%,_posts/%, $(MARKDOWN))
jekyll-build : $(POSTS)
...
_posts/%.md : source/%.md
...

'Protoc' command in a parent directory outputs entire source directory in the python_out directory

I have a directory named protos which holds a single .proto file, but will eventually hold many. This directory has a sibling named app , where I would like to dump the built grpc python files.
I'm trying to write a simple bash script that will invoke the protoc command and build .proto files in protos, and output the built files to app
Below is a tree of where I've placed each file.
├── build_protos.sh
└── trainingInstance (root module directory)
|
├── app
│   ├── app.py
| ├── (where I'd like my built files to go)
| |
| └──trainingInstance
| └──protos
| └──(where the built files actually go)
|
└── protos
└── TrainingService.proto (what I'd like to compile)
When I run build_protos.sh, the file TrainingService.proto is detected fine and built, but instead of placing the built file into ...trainingInstance/app/<file> , it instead places it in ...trainingInstance/app/trainingInstance/protos/<file> (see above).
I thought I had solved this problem by explicitly setting the proto_path to protos, but it doesn't seem to care either way. Below is my build_protos.sh file:
#!/bin/bash
working_dir=$(pwd)
proto_dirs=($(pwd)/trainingInstance)
for dir in $proto_dirs
do
srcdir=$dir/protos #./trainingInstance/protos
destdir=$dir/app #./trainingInstance/app
echo Building $dir protos...
python3 -m grpc_tools.protoc\
-I $working_dir\
--proto_path=$srcdir\
--python_out=$destdir\
--grpc_python_out=$destdir\
$srcdir/*.proto #./trainingInstance/protos/*.proto
done
So does anyone know how to stop protoc from making these reflected directories in the output directory? Any help is appreciated.
Not 5 minutes after posting this question (after previously playing with the script for an hour), I've solved my own problem: the -I flag, which is pointed to my working-directory, forces protoc to build files in this manner, since it aims to keep different .proto packages separate. This issue is fixed by removing the -I flag entirely.
I feel I should leave this here in-case anyone else has a similar issue.

Sphinx: specify html path distinct from BUILDDIR/html?

In the sphinx Makefile, let's say I specify:
BUILDDIR = buildy_mcbuildface
So that make html creates the documentation webpage under buildy_mcbuildface/html. This is a slight annoyance in that the contents of the html folder must be copied to the server location after each build.
Can I specify the html path directly, or is it always built under $BUILDDIR/html? I have looked at the html options, and I see no such path option.
Here's the solution I came up with:
Add to the Makefile:
HTMLCOPYDIR = /path/to/server/location
and also in the Makefile change, add:
cp -rT $(BUILDDIR)/html $(HTMLCOPYDIR)
after the line:
#$(SPHINXBUILD) -M $# "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

How to use xgettext iteratively to update .po files for translation

I'm looking at using xgettext to aid translation of large codebase, and I have two questions:
if I have one .po file per-language, is there an easy way to update them all using a single xgettext scan of the codebase, or must I run xgettext once for each language?
if I add the target langauge to the .po file header with poedit, xgettext seems to overwrite this with default headers. How can I stop this?
Maybe I'm using the wrong tool, in which case suggestions are welcome. What I want is to be able to scan the code and update the .po files with any new strings, but leaving any header information intact.
EDIT: I know that poedit can scan code, but I was hoping to find a command line application to perform the scanning to automate the process more easily.
Yes, basically you're using the tools wrong.
xgettext extracts the tags and creates the template file. (e.g. *.pot file)
The msgmerge command updates a .po file with changes from the .pot file.
We have make rules to update the .po files, like the one below:
%.en.po : %.pot
-[ -e $# ] && msgmerge --width=110 --update $# $<
[ -e $# ] || cp $< $#

Resources