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

a18n

v1.12.4

Published

Automated I18n solution for JavaScript/TypeScript/React, effortlessly add I18n support for existing projects.

Downloads

440

Readme

a18n - automated i18n solution

npm package Coverage

English | 中文

a18n is a production-ready internationalization solution that aims for maximum automation and simplicity.

It can wrap and extract texts in JavaScript/TypeScript code using AST manipulation, so you can effortlessly add i18n support to new or existing projects.

With its ability to recognize texts and resources, it can check for untranslated texts in code and resources, prune unused resources, and automatically provide texts context both for extraction and translation.

Screen Recoding

Features

  • Command Line Tool
    • Wrap texts with translation calls (a18n wrap). (English and CJK texts are currently supported)
    • Extract texts from translation calls (a18n extract)
    • Check for untranslated text in code and resources (a18n check)
    • Replace untranslated text with translations (a18n replace)
    • Purge translation calls and imports (a18n purge)
    • Supports dynamic texts in ES6 Template Strings
    • Supports TypeScript
    • Supports React and any JSX framework
    • Provides context for texts with the corresponding module
  • Runtime
    • Translates both static and dynamic texts using provided locale resources
    • Small - only ~200 lines of code
    • Optimized for performance - dynamic texts are compiled into a template on the first run for maximum speed.

Getting Started

WARNING: Existing project code will be modified. Please make a backup or commit before proceeding.

Install as a project dependency (not a devDependency, as a18n provides both a CLI and runtime)

npm install --save a18n

Scan and modify code files (.js, .ts, .jsx, .tsx) in the src directory. This will wrap plain text strings with translation calls:

  • --namespace serves to avoid conflicts with the same a18n instance from other dependencies
  • --module-name automatically provides context for each text and helps distinguish texts from different modules
  • --text=cjk wraps CJK texts. You can also use --text=capitalized to wrap English words or sentences
npx a18n wrap src --write --namespace="my.unique.project.id" --module-name="fileDirAndName" --text="cjk"

Manually check for unintended modifications and fix them. You can:

  • Use the comment // @a18n-ignore to ignore the next line
  • Use the comment /* @a18n-ignore-file */ to ignore the entire file

Extract texts passed to translation calls (this will generate zh-CN.json, en.json in the ./locales directory):

npx a18n extract src ./locales --locales zh-CN,en

Translate resources under ./locales (e.g. from Chinese to English). After this, you should have something like this: (the key is added by the a18n tool, the value is filled in by a human translator)

{
  // missing translation, will fallback to original key
  "no-translation": null,

  // static text
  "早上好": "Good morning",

  // dynamic text
  "%s是最好吃的": "pizza is better than %s",

  // with module context
  "some.module: {
    "%s是最好吃的": "noodle is better than %s",
  }
}

Load translation resources and specify the language at the start of your application, this must be done BEFORE running any other code

import a18n from 'a18n'
import en from './locales/en.json'

a18n.addLocaleResource('en', en)
a18n.setLocale('en')

// now, a18n() will produce translated result
a18n('早上好') // === "Good morning"

const food = 'A'
a18n`${food}是最好吃的` // === "pizza is better than A"

Documentation

API

a18n(text)

This function can and should be auto-added by a18n wrap command

Translates static text, text should be literal string (instead of a variable). For example:

a18n('你好') // good
a18n(greeting) // bad, `a18n extract` cannot extract "你好" by analyzing code

a18n`text${variable}`

This function can/should be auto-added by a18n wrap command

Translates dynamic text.

This is an ES6 syntax called Tagged Template Literal

a18n.x`text${variable}`

This function cannot be auto-added and should be added by user.

Translates dynamic text and returns an array containing translated parts.

This method is useful for displaying mixed content.

const greeting = <div>{a18n.x`Hello ${<strong>Jimmy<strong>}`}</div>
// could evaluate to:
// <div>你好 <strong>Jimmy<strong></div>

a18n.setLocale(locale)

Set locale to use.

This method should be called BEFORE every a18n translation functions are called.

a18n use navigator.language as the initial value.

a18n.addLocaleResource(locale, resource)

Adds a resource for the specified locale. The resource is usually extracted using the a18n extract command.

An example resource:

{
  // missing translation, will fallback to the original key
  "no-translation": null,

  // static text
  "早上好": "Good morning",

  // dynamic text
  "%s是最好吃的": "pizza is better than %s"

  // the resource can be organized by module, it can then used by the corresponding instance,
  // created from `getA18n('my-project-namespace', 'my.module.x')`
  "my.module.x": {
    "你好": "Hello from my module",
  }
}

Will merge with existing resource and overwrite values that have same keys.

This method should be called BEFORE every a18n translation functions are called.

a18n.getA18n(namespace, moduleName?)

this method is usually auto added with a18n wrap command, with --namespace option

Get an a18n instance with the specified namespace and modules.

You can use a unique namespace to get isolated resources and locales, even if different parts of system are reusing a18n as common dependency (which is common in large projects).

If moduleName is provided, this a18n instance will select resource[moduleName] as the resource. This serves as a way to split resources into different modules.

See Q & A for more background.

a18n.DEBUG_setRepeat(repeatCount, separator?)

Repeats the translated string/array multiple times, so that UI issues like text overflow can be easily spotted.

  • repeatCount: how many times to repeat the text
  • separator: separator between repeated text, default to (a space)

CLI

See: npx a18n --help

Q & A

1. Why is it important to load translation resources and specify a locale **before ** all other code is run?

This can be illustrated with this example:

const s = a18n('apple') // We don't have locale resources yet, so `s` is bound to 'apple', not '苹果' as we intended.

a18n.addLocaleResource('zh-CN', { apple: '苹果' }) // ...Too late
a18n.setLocale('zh-CN') // ...Too late

console.log(s) // 'apple'

It is important to load translation resources and specify a locale before all other code is run because if you don't, the a18n function may not have access to the correct translation resources and locale, and will default to the original text.

2. When do I need to specify a namespace?

If there are multiple dependencies in the project that further depend on a18n, some bundling tools (such as webpack) may generate a bundle where they all share a single copy of the a18n code and a single copy of the a18n instance at runtime. Since a18n is a singleton, this may cause unintended locale resource sharing/conflict.

To solve this problem, different dependencies can get their own a18n instances, differentiated by namespace, using getA18n(namespace), and continue to have isolated resources and language configurations. It is also possible to acquire the same a18n instance by specifying the same namespace in order to share language and translation resources.