npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@medic/translation-checker

v1.1.0

Published

Check translations from [.properties](https://en.wikipedia.org/wiki/.properties) files with [Mustache](http://mustache.github.io/) placeholders markup or [messageformat](https://messageformat.github.io/messageformat/) syntax.

Downloads

9,532

Readme

translation-checker

Check translations from .properties files with Mustache placeholders markup or messageformat syntax.

Getting started

Node 8.10+ required. Install with:

$ npm install @medic/translation-checker

Here is how you can use it:

const {
  checkTranslations,
  TranslationException
} = require('@medic/translation-checker');

const dir = `${somePath}/translations`;
let fileNames;
try {
  fileNames = await checkTranslations(dir);
  // Your files passed the validations!
  // fileNames = ['messages-en.properties', 'messages-es.properties', ...]
} catch (err) {
    if (err instanceof TranslationException) {
      // Oops, translation errors !!
      fileNames = err.fileNames;  // ['messages-en.properties', 'messages-es.properties', ...]
      if (!err.errors) {
        return log.error('Exception checking translations:', err.message);
      }
      for (const error of err.errors) {
        switch (error.error) {
          case 'cannot-access-dir':
            return log.warn('Could not find custom translations dir:', dir);
          case 'missed-placeholder':
          case 'wrong-placeholder':
            log.error(error.message);
            break;
          case 'missing-key':
          case 'empty-message':
            // less severe, lets log it with WARN severity instead of ERROR
            log.warn(error.message);
            break;
          default:  // 'wrong-messageformat', 'wrong-placeholder'
            // This are more severe errors
            log.error(error.message);
            break;
        }
      }
    } else {
      throw err;  // unexpected ;(
    }
}

Logs from the example above will look like:

WARN Empty message found for key 'report.pregnancy.u_lmp_date' in 'en' translation 
WARN Empty message found for key 'report.pregnancy.method_lmp' in 'en' translation 
ERROR Cannot compile 'es' translation with key 'Number in month' has placeholders that do not match any in the base translation provided 
ERROR Cannot compile 'es' translation n.month = '{MONTHS, plural one{1 mes} other{# meses}}' : Expected "," but "o" found.

Arguments

checkTranslations(dir, options) (async)

  • dir: the directory to scan
  • options.languages: Array of lowercase ISO 639-1 code languages to be checked. Defaults to all valid files found in dir.
  • options.checkPlaceholders: Whether to check missed placeholders or not. Defaults to true.
  • options.checkMessageformat: Whether to check wrong Messageformat or not. Defaults to true.
  • options.checkEmpties: Whether to check empty messages or not. Defaults to true.
  • options.checkMissing: Whether to ensure all keys in "en" file also exist in other languages. Defaults to false.

Error details

All the errors raised by checkTranslations() are instances of TranslationException. The exception object has an errors array with one object for each error detected as following:

{
  "lang": "en",                     // The language where the error was found
  "error": "wrong-messageformat",   // The error code
  "key": "n.month2",                // The translation key
  "message": "Cannot compile ..."   // A message with more details about the error
}

These are the error codes and what they mean:

  • cannot-access-dir - the directory passed doesn't exist or is not accessible
  • wrong-file-name - one of the translation files has a wrong name or has an unknown ISO 639 language code on it, eg. messages-e$.properties
  • missed-placeholder - a mustache placeholder eg. {{firstName}} was found in a translation, but main translations ('en' or 'ex') don't have placeholders for that translation at all
  • wrong-placeholder - a mustache placeholder eg. {{firstName}} was found in a translation that do not match any in the base translations ('en' or 'ex') placeholders
  • empty-message - empty message found in a translation
  • missing-key - a key was found in the English translation file but not found in one of the other languages

Placeholders check

The mustache placeholder check works as following:

  • You need to call checkTranslations(dir, options) with options.checkPlaceholders = true (default).
  • options.languages needs to be unset (default) or set at least with one or both of the two codes considered "template" languages: 'en', 'ex'
  • 'ex' is not a real ISO language code, but if you have a messages-ex.properties file, you can place there placeholders that can be used for a specific key, eg. hello = {{firstName}} {{lastName}} {{username}}
  • 'en' language (messages-en.properties) is considered the "template" or base language, and any placeholder used in any other translation file other than 'en' or 'ex' needs to be present in one of these two templates. Eg. if you have in the 'en' translation the following translation records.total = {{count}} records, this is a valid 'es' translation: records.total = {{count}} registros but this not: records.total = {{count}} registros de {{max}}. You can use the {{max}} placeholder either adding it to the 'en' translation or adding an entry in the messages-ex.properties file like this: records.total = {{max}} (or records.total = {{count}} {{max}})

Check the JSDoc of the source code to see more options.

Messageformat check

"Messageformat" check are also performed by default, you can disable it with options.checkMessageformat = false.

A common error is by mistake translate the messageformat keywords when using online translator tools, eg. this translation that is OK in English:

n.month = {MONTHS, plural, one{1 month} other{\# months}}

Wrong translated to Spanish:

n.month = {MONTHS, plural, uno{1 mes} otros{\# meses}}

Will raise an error with a the message:

Invalid key `uno` for argument `MONTHS`. Valid plural keys for this locale are `one`,
`other`, and explicit keys like `=0`

The right translations is:

n.month = {MONTHS, plural, one{1 mes} other{\# meses}}

Empty message checks

Validations fail if a key is found like this:

n.month = 

But some times empty keys are acceptable because the software that use the translations fallback to the default language, so to disable empties check set options.checkEmpties to false (default is true).

Publishing

$ npm publish --access=public