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

@instructure/i18nliner-handlebars

v2.0.0

Published

handlebars i18n made simple

Downloads

4,292

Readme

I18nliner

Build Status

yay readme-driven development!

TODO

  • grunt/broccoli/etc:
    1. preprocessor (generate templates w/ all block t calls converted to inline t calls)
    2. extractor (get all inline translation strings)
      • this should probably actually be implemented in i18nliner-js; we can just register ourselves with it somehow
  • basic handlebars helper
  • ember support
    • bound helper support
    • ability to nest link-to (and possibly others) in a block translation (like we do in i18nliner.rb)
  • bower

====

I18nliner is I18n made simple.

No .js / .json translation files. Easy inline defaults. Optional keys. Easy pluralization. Wrappers and blocks, so your templates look template-y and your translations stay HTML-free.

TL;DR

I18nliner lets you do stuff like this:

{{t "Ohai %{user}, my default translation is right here" user=user}}

and even this:

{{#t}}
  Hey {{amigo}}!
  Although I am <a href="/">linking to something</a> and have some
  <strong>bold text</strong>, the translators will see <strong><em>
  absolutely no markup</em></strong> and will only have a single
  string to translate :o
{{/t}}

Features

No more .js/.json translation files

Instead of maintaining .js/.json files and doing stuff like this:

I18n.t('account_page_title');

Forget the translation file or anything in your .js files, and just do this in your handlebars:

{{t "account_page_title" "My Account"}}

Regular I18n options follow the (optional) default translation, so you can do the usual stuff (placeholders, etc.).

Okay, but don't the translators need them?

Sure, but you don't need to write them. Just run:

i18nliner dump

This extracts all default translations from your codebase, merges them with any other ones (from pre-existing translation files), and outputs them to locales/generated/translations.json (or .js if using i18n.js)

TODO grunt/broccoli instructions/links

It's okay to lose your keys

Why waste time coming up with keys that are less descriptive than the default translation? I18nliner makes keys optional, so you can just do this:

{{t "My Account"}}

I18nliner will create a unique key based on the translation (e.g. 'my_account'), so you don't have to. See I18nliner.inferred_key_format for more information.

This can actually be a good thing, because when the en changes, the key changes, which means you know you need to get it retranslated (instead of letting a now-inaccurate translation hang out indefinitely). Whether you want to show "[ missing translation ]" or the en value in the meantime is up to you.

Wrappers and Blocks

The Problem

Suppose you have something like this in your template:

<p>
  You can <a href="/new">lead</a> a new discussion or
  <a href="/search">join</a>
</p>

You probably don't want the HTML as part of the translation, because it makes things brittle and potentially insecure. At the same time, you probably want the translators to get the entire sentence with minimal noise. So what do you do?

Wrappers

I18nliner lets you specify wrappers, so you can keep HTML out the translations, while still just having a single string needing translation:

<p>
  {{t "You can *lead* a new discussion or **join** an existing one."
      w0="<a href=\"/new\">$1</a>"
      w1="<a href=\"/join\">$1</a>"
  }}
</p>

Delimiters are increasing numbers of asterisks.

Blocks

But wait, there's more!

Perhaps you want your templates to look like, well, templates. Try this:

<p>
  {{#t}}
    Welcome to the internets, {{user.name}}
  {{/t}}
</p>

Or even this:

<p>
  {{#t}}
    <b>Ohai {{user.name}},</b>
    you can <a href="/new" title="{{some helper}}">lead</a> a new discussion or
    <a href="/search">join</a> an existing one
  {{/t}}
</p>

In case you're curious about the man behind the curtain, I18nliner adds a pre-processor that turns the second example into something like this during Handlebars parsing:

<p>
  {{t "some_unique_key"
      "*Ohai %{user_name}*, you can **lead** a new discussion or ***join*** an existing one."
      user_name=(user.name)
      w0="<b>$1</b>"
      w1=(__i18nliner_concat "<a href=\"/new\" title=\""
                             (__i18nliner_escape (some helper))
                             "\">$1</a>")
      w2="<a href="/search>$1</a>"
  }}
</p>

In other words, it will infer wrappers from your (balanced) markup, and will create placeholders for any other (inline) handlebars expressions. Block helpers (e.g. {{#if cond }}...) are not supported within a block translation. The only exception to this rule is nested translation calls, e.g. this is totally fine:

{{#t}}
  Be sure to
  <a href="/account/" title="{{#t}}Account Settings{{/t}}">
    set up your account
  </a>.
{{/t}}

TODO grunt/broccoli instructions/links for enabling pre-processing

HTML Safety

I18nliner ensures translations, interpolated values, and wrappers all play nicely (and safely) when it comes to HTML escaping. If any translation, interpolated value, or wrapper is HTML-safe, everything else will be HTML- escaped.

Related Projects