Internationalization (i18n) Implementation for JSP/VM Frontend Using Gettext and Easygettext
This article describes a frontend engineer's exploration of i18n for JSP and VM pages, detailing the challenges of hard‑coded strings, the use of jquery‑i18next, gettext tools, a custom i18n‑gettext npm package, Makefile automation, and the resulting workflow for extracting, merging and compiling translation files.
The project aims to make the backend of a travel platform more international‑friendly by introducing i18n support for pages rendered with JSP, VM, jQuery, Mustache and custom string files.
Project Background
International suppliers need a localized backend, so the team began exploring internationalization (i18n) practices.
Project Overview
i18n stands for "internationalization" (the 18 letters between i and n are omitted). The focus of this article is on handling JSP, VM, and jQuery+Mustache+string files.
Initial Exploration
Front‑back Interaction Flow
The user request includes an Accept-Language header and a cookie storing the language‑pack version. The backend decides whether to return a new language pack or use the cached one from LocalStorage .
Language Pack and Page Rendering
Typical i18n libraries such as jquery-i18next require both i18next and the jQuery plugin. Example DOM structure:
<div id="page">
<ul class="nav">
<li><a href="#" data-i18n="nav.home">主页</a></li>
<li><a href="#" data-i18n="nav.page1"></a></li>
<li><a href="#" data-i18n="nav.page2"></a></li>
</ul>
</div>Corresponding language‑pack JSON:
{
"nav": {
"home": "Home",
"page1": "Page One",
"page2": "Page Two"
}
}Calling $("#page").localize(); replaces all elements with a data-i18n attribute inside the #page scope.
Problems with the current approach include repeated rendering, difficulty extracting hard‑coded strings into a single JSON file, poor separation of translation work, and string reuse issues.
Final Solution Determination
The team decided to adopt GNU gettext tooling. While xgettext can extract strings from many languages, it does not support .string or .mustache files, so the easygettext npm package is used for those.
Example of easygettext supported markup:
<div translate>Hello World</div>
<div placeholder="Hello World"></div>
<translate>Hello World</translate>A custom npm package i18n-gettext provides two CLI commands: gettext-extract (extracts markers from VM/template files) and gettext-compile (compiles .po files to JSON). The extraction process is orchestrated by a Makefile:
.PHONY: clean makemessages vmMakemessages translations
makemessages: /tmp/template.pot
clean:
rm -f /tmp/template.pot
translations: ./$(LANG_DIR)/translations.string
mkdir -p $(LANG_DIR)
gettext-compile --dir ./$(LANG_DIR)/ $(LOCALE_FILES)Key extraction commands:
gettext-extract --startDelim "[#" --endDelim "#]" --quiet --attribute i18n \
--output $@ $(GETTEXT_TEMPLATE_SOURCES)
xgettext --language=JavaScript --keyword=i18n \
--from-code=utf-8 --join-existing --no-wrap \
--output $@ $(GETTEXT_JS_SOURCES)Sample .po entry generated:
#: path/to/file.js:618
msgid "建议至少在当天的 {hour}:{minute} 前预定"
msgstr "Recommend to book at least {hour} hours {minute} minutes before departure."Template files are marked with the custom delimiter [# ... #] so that extraction does not heavily intrude existing code:
<th>[# '你好,世界' | i18n #]</th>In JavaScript, strings are wrapped with QNR.i18n to include variables:
str = QNR.i18n("建议至少在当天的 {hour}:{minute} 前预定", { hour: hour, minute: minute });Advantages of this approach include minimal code intrusion, automatic merging of old translations, clear separation of extraction and translation tasks, and better semantic context for translators.
Remaining issues are handling input‑heavy VM fragments, manual upload of generated JSON language packs, and the need for further automation.
Qunar Tech Salon
Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.