# jquery.i18n turns JSON message files into a live interface

> jquery.i18n is a Wikimedia JavaScript internationalization library that reads the banana JSON message format used by MediaWiki, applies CLDR plural rules, gender and grammar forms, and can switch the interface language without a page reload. It is a jQuery plugin and the npm package is published under a dual MIT or GPL-2.0-or-later licence.

**wikimedia/jquery.i18n** — 🌐 jQuery based internationalization library

- Repository: https://github.com/wikimedia/jquery.i18n
- Stars: 737 · Forks: 181
- Language: JavaScript
- License: GPL-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/wikimedia-jquery-i18n

## A jQuery plugin from the Wikimedia Language Engineering team

jquery.i18n is a jQuery based JavaScript internationalization library, and it helps you to internationalize your web applications easily.

The provenance explains a lot about the design. It is a project by the Wikimedia Foundation's Language Engineering team, and it is used in some of the Wikimedia Foundation projects like Universal Language Selector. The library uses a json based localization file format, banana, which is used as the localization file format for MediaWiki and other projects.

That last point is the single most important fact for an adopter. The file format is not invented for this library, it is a format with existing tooling, existing translators and existing conventions behind it. MediaWiki's own language files and the jquery.uls project's i18n directory are both pointed at in the README as real examples to read.

The package is published on npm as @wikimedia/jquery.i18n, and the repository holds a src directory, a demo directory, a test directory and a libs directory, with a Gruntfile.js and a .gitmodules file, so there is a submodule component to the build.

There is also a note at the top of the README: for the jQuery independent version of this library, see banana-i18n. The two projects share the format, and that note is the cleanest statement of when to use which.

## Getting the source and running the demo

The quick start is a clone plus a submodule update, because the repository carries a submodule.

```bash
git clone https://github.com/wikimedia/jquery.i18n.git
cd jquery.i18n
git submodule update --init
```

Skipping the submodule update step leaves you with a tree that is missing part of what the tests and the build expect, and the failure would look like a missing file rather than a missing submodule.

The test dependencies are installed with npm:

```shell
npm install
```

and the tests are run with npm test, which the README says will run the tests. The package.json shows what that means under the hood: the test script is grunt test --verbose, and the dev dependencies include grunt, grunt-contrib-qunit for the browser based test runner, qunit, jquery at version 3.5.1 and the eslint configuration for Wikimedia.

The demo is served rather than opened from the filesystem, because the message files are loaded over HTTP:

```bash
# If you're using python3, open demo as a local server using port 8000
python -m http.server
# If you're using python2, use this command instead
# python -m SimpleHTTPServer  
```

Then you open localhost:8000/demo in your browser and the demo index page appears. The repository carries a demo directory with an index.html, a playground.html and an extendedParser.html, plus a demo/i18n directory holding the message files the demo uses.

## One file per language, or one file for everything

The message files are JSON, and the library supports two layouts, and the README is clear that the choice is a collaboration decision rather than a technical one.

The per-language layout is a folder named i18n inside your source code, with one file per language or locale named like the language code:

```
App
	|--src
	|--doc
	|--i18n
		|--ar.json
		|--de.json
		|--en.json
		|--he.json
		|--hi.json
		|--fr.json
		|--qqq.json
```

The single-file layout puts every language in one document, keyed by language code:

```json
{
	"@metadata": {
		"authors": [
			"Alice",
			"David",
			"Santhosh"
		],
		"last-updated": "2012-09-21",
		"locale": "en",
		"message-documentation": "qqq",
		"AnotherMetadata": "AnotherMedatadataValue"
	},
	"en": {
		"appname-title": "Example Application",
		"appname-sub-title": "An example application with jquery.i18n",
		"appname-header-introduction": "Introduction",
		"appname-about": "About this application",
		"appname-footer": "Footer text"
		},
	"ml": {
		"appname-title": "അപ്ലിക്കേഷന്‍ ഉദാഹരണം",
		"appname-sub-title": "jquery.i18n ഉപയോഗിച്ചുള്ള അപ്ലിക്കേഷന്‍ ഉദാഹരണം",
		"appname-header-introduction": "ആമുഖം",
		"appname-about": "ഈ അപ്ലിക്കേഷനെപ്പറ്റി",
		"appname-footer": "അടിക്കുറിപ്പു്"
	}
}
```

The README's advice is that per-language files are more convenient for collaboration, version controlling, scalability and so on, and that the single file suits an application that is not big. It also notes that in the single-file approach a language code can be given as a file name instead, so the two styles can be mixed inside one file.

For a project that wants to use translatewiki.net, the per-language layout is the one that works, because that platform commits one file per language to the repository.

## Metadata, message keys and the qqq documentation locale

Two conventions in the format are worth understanding before you write a single message.

The first is the @metadata block, which holds all kind of data that are not messages. You can store author information, copyright, updated date or anything there, and the README is explicit that author and metadata information is not lost anywhere, unlike other formats that use comments for this. That is a real difference from, say, a properties file, and it matters for a project with a translation memory workflow.

The second is the message key convention. Messages are key-value pairs, and it is a good convention to prefix your appname to message keys to make the messages unique, since it acts as the namespace for the message keys. The convention is also to have the message keys with - separated words, all in lower case.

The qqq locale is the third piece, and it is the one most projects overlook. The feature list describes message documentation through special language code qqq, and the example message file includes a qqq.json alongside the real locales. A qqq file holds the documentation for each message, which is what a translator reads to know what a message means and when it should be used. If you adopt the library without a qqq file, your translators get strings with no context, and the platform is where that documentation usually comes from.

The file must be valid JSON, and the README shows the metadata block with a mixture of known keys, such as authors, last-updated, locale and message-documentation, and arbitrary ones like AnotherMetadata.

## Plurals, gender and grammar without message duplication

The feature that distinguishes this library from a simple key lookup is the message grammar.

Placeholders use the MediaWiki convention, so a message reads There are $1 cars, which the README calls an easily readable and proven convention.

Plural conversion is supported without using extra messages for all plural forms, and the rule handling is done using CLDR, covering a wide range of languages. That distinction is the one to hold on to. The usual approach in other i18n libraries is to require a separate message key per plural form, for example one key for zero, one for one and one for other, and the translator has to guess that all three exist. With CLDR rules the library computes the form from the count and the locale, so a missing translation surfaces as a missing key rather than as a wrong sentence.

Gender is handled by passing the gender value, and you get correct sentences according to gender. Grammar forms are supported too, and the README is honest that jquery.i18n has a basic but extensible grammar conversion support.

These constructs can be nested to any arbitrary level, which is what makes the grammar support usable for real sentences rather than just a plural suffix.

Two smaller features complete the picture. There is a data api, where the message key comes from an attribute such as <li data-i18n="message-key"></li>, and dynamic change of interface language without refreshing a webpage, which is the feature that makes an in-app language picker possible without a full reload.

## Translators, the extended parser and the licence

The README describes three translation routes, and it is the route you choose that determines how much infrastructure you need.

Editing the JSON files directly suits translators with a technical background, and it also suits a small application with only a small number of languages. Providing a translation interface alongside your application suits proprietary or private applications with a significant amount of translators. And using open source translation platforms like translatewiki.net is described as highly recommended for an open source application that wants to be localized to as many languages as possible with the maximum number of translators, since MediaWiki and jquery.uls both use it and it can update your code repository at regular intervals with updated translations.

The message parser is extensible, so you can add or customise magic words in messages, with {sitename} and [[link]] given as examples. The demo directory carries an extendedParser.html page, which is where the README's own example for that feature lives.

On licensing, there is a detail that catches people. The repository contains both a GPL-LICENSE and an MIT-LICENSE file, and the package.json license field reads (MIT OR GPL-2.0-or-later). So the library is dual licensed: you can use it under the MIT terms or under GPL-2.0-or-later, and the choice is yours. The MIT option is what makes it usable inside a proprietary application, which matters for the translation interface route above.

The package version in package.json reads 1.0.10, and the most recent GitHub release tag is v1.0.9 from 2023-06-12, with the last push on 2026-07-23. The engine field still declares node >=4.0.0, which is a leftover from the era when this library was first written and says nothing about what the test tooling needs today.

## Conclusion

jquery.i18n suits a team that already ships JSON message files in the banana format, or that wants to adopt the same format MediaWiki and translatewiki.net already use, since the plural, gender and grammar handling follows CLDR rather than a home grown scheme. It is the wrong tool if your project is not on jQuery, because the library is a jQuery plugin, and the README points to the jQuery independent banana-i18n for that case. Before adopting it, decide between one file per language and a single file for all languages, because the README is explicit that per-language files are more convenient for collaboration and version control, and set up the qqq documentation locale alongside your message files.

## FAQ

### How do I install and test jquery.i18n?

Clone the repository, then run git submodule update --init so the submodule is present, then npm install to fetch the dev dependencies and npm test to run the tests. The test script is grunt test --verbose, using grunt-contrib-qunit and qunit with jquery 3.5.1.

### What is the banana message file format?

It is the json based localization file format used by jquery.i18n, MediaWiki and other projects. Message files hold @metadata for non-message data such as authors and update dates, and key-value message pairs, with a per-language file layout or a single file keyed by language code, and a language code value may also point at a file path.

### How does jquery.i18n handle plurals and gender?

Plural conversion works without extra messages for every plural form, and the rule handling uses CLDR so it covers a wide range of languages. Gender is handled by passing the gender value, and grammar forms are supported with what the README describes as a basic but extensible grammar conversion support.

### Can I use jquery.i18n without jQuery?

Not this package. The README notes that for a jQuery independent version of the library you should see banana-i18n, which implements the same message format without the jQuery dependency.

### What licence does jquery.i18n use?

It is dual licensed. The package.json license field reads (MIT OR GPL-2.0-or-later), and the repository carries both a GPL-LICENSE and an MIT-LICENSE file, so you can use the library under either set of terms.

## Sources

- [Issues](https://github.com/wikimedia/jquery.i18n/issues)
- [License: GPL-2.0](https://github.com/wikimedia/jquery.i18n/blob/master/LICENSE)
- [README](https://github.com/wikimedia/jquery.i18n/blob/master/README.md)
- [Releases](https://github.com/wikimedia/jquery.i18n/releases)
- [wikimedia/jquery.i18n on GitHub](https://github.com/wikimedia/jquery.i18n)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/wikimedia-jquery-i18n
