Internationalizing &
Localizing Your Modern
Javascript App
$ whoami
I’m Johnathan. I work at Airware on the cloud
platform for managing fleets of drones. Before that,
I worked at LinkedIn.
github.com/jleppert, blog @ stuffzies.com
i18n and translating apps is a reoccurring project
for me.
It can be painful, or fun.
Overview
• Why?
• STANDARDS@@@!! Review of the current state
• Strings/Messages: Example App & Code
Why should we translate our
apps?
• More users….? Quicker time to market than competitors.
• Enforce good design principles from day one
• It’s really hard and tedious after you have a lot of code
that didn’t care about it or consider it
• Bolted on i18n usually looks half-baked and janky —
you’ll have to make compromises
• Today’s apps are conversational. More than just about
button labels.
Goals
• Clean, simple workflows: developer first. Shouldn’t
“get in the way”
• Works on server/client with same idioms/API and, if
possible, code
• Shared messages resources for your translators or
translations provider
• Output is cacheable, strings sent down in javascript
bundles
Isn’t there a standard for
this? Kind of…
• ECMA-402 (2012)
• INTL object — available in the latest browsers, and,
now, node (v0.12 mainline — only en_US. Other
locales need a compile option). CLDR data is big.
• INTL.DateTimeFormat - Date formatting
• INTL.NumberFormat - Number formatting
• INTL.Collator (sorting)
ECMA-402: Locale
• Accept-Language standard: IETF (en_US)
• Scripts (zh-Hans, zh-Hant, sr-Cyrl, sr-Latn, etc)
• Unicode extensions: ja-JP-u-ca-japanese
How to use INTL
Step 0: Getting the user’s locale
Sadly, there is no defined API. navigator.language
(chrome/FF) and navigator.browserLanguage in IE,
or read the Accept-Language header.
I prefer to make an intelligent guess, then ask the
user — have it preselected. Store locale (string, e.g.
“en_US”) a cookie that is independent of your
session cookie.
Localizing Dates
new Intl.DateTimeFormat(“es”,
{month:"long"}).format(d)
'Febrero'
new Intl.DateTimeFormat("es",
{month:"long",day:"numeric"}).format(d)
'11 de febrero’
** Use an empty array as the first argument to use the user’s default (browser) locale. May
not be correct, however.
Numbers!!
> new Intl.NumberFormat(“en-US").format(1234.5678);
'1,234.568'
> new Intl.NumberFormat("de").format(1234.5678);
'1.234,568'
> new Intl.NumberFormat("fr").format(1234.5678);
'1 234,568'
> new Intl.NumberFormat("en-US",{style:"percent"})
.format(.023);
'2.3%'
Collation
var coll = new Intl.Collator(['en'], { sensitivity: 'base',
ignorePunctuation: true });
base = a = á, etc.
coll.compare('Bluebird', ‘bluebird') === 0, case is ignored.
coll.compare(‘blackbird’, ‘black-bird’) === 0, punctuation ignored
coll.compare('bluebird', ‘blackbird') === 1, (“u” is after “a”)
What about strings?
Something old, something new: gettext
• It works
• Handles pluralization and positional interpolation
• Use the existing ecosystem of tools, translation
providers
• Template-system, framework agnostic
An example app
• https://github.com/jleppert/rosetajs/
• Using Dust, Jed, po2json, browserify
• Same workflow client or server
• Same message format, code, helpers.
Developer API
• The @i18n template helper.
• {@i18n singular="Hello, {first_name}, you have
one message." plural="Hello, {first_name}, you
have {message_count} messages!"
value=“{message_count}"/}
• API: i18n.translate(‘Hello, {first_name}, you have
a new message!!.’, { first_name: ‘johnathan’});
How does it work?
• Template files and javascript source are read, an AST is
constructed and the @i18n helper calls/API are used to
create a .po file.
• xgettext - extracts translatable strings. I wrote a version that
understands javascript and dust templates, but you can do
so for most any language.
• po files are sent to translators, where they translate the
messages/re-arrange placeholders, etc.
• The right po file is selected based upon the user’s selected
locate and used during template helper/translation API
Let’s see it work
http://localhost:8000
Considerations
• Organize templates by feature (hopefully…)
• Automated tar of po files, send to translators via CI system
• Translate by feature: “this feature is available in english, french,
and spanish will be launched 6/10”
• Suffix files by locale for easy organization and co-locate them
• Check files into some source control project: receive translations
out of order from deployment
• Consider adopting a pirate-speak locale — getttext project has
many such manglers for po files
Thanks, and here’s some
More info
• Mailing List: http://jsi18n.com
• Gettext Overview: https://developer.mozilla.org/en-
US/docs/gettext
• PO/POT Format:
http://pology.nedohodnik.net/doc/user/en_US/ch-
poformat.html
• JS Gettext Implementation:
http://slexaxton.github.io/Jed/
• po2json: https://github.com/mikeedwards/po2json

I18n

  • 1.
  • 2.
    $ whoami I’m Johnathan.I work at Airware on the cloud platform for managing fleets of drones. Before that, I worked at LinkedIn. github.com/jleppert, blog @ stuffzies.com i18n and translating apps is a reoccurring project for me. It can be painful, or fun.
  • 3.
    Overview • Why? • STANDARDS@@@!!Review of the current state • Strings/Messages: Example App & Code
  • 4.
    Why should wetranslate our apps? • More users….? Quicker time to market than competitors. • Enforce good design principles from day one • It’s really hard and tedious after you have a lot of code that didn’t care about it or consider it • Bolted on i18n usually looks half-baked and janky — you’ll have to make compromises • Today’s apps are conversational. More than just about button labels.
  • 5.
    Goals • Clean, simpleworkflows: developer first. Shouldn’t “get in the way” • Works on server/client with same idioms/API and, if possible, code • Shared messages resources for your translators or translations provider • Output is cacheable, strings sent down in javascript bundles
  • 6.
    Isn’t there astandard for this? Kind of… • ECMA-402 (2012) • INTL object — available in the latest browsers, and, now, node (v0.12 mainline — only en_US. Other locales need a compile option). CLDR data is big. • INTL.DateTimeFormat - Date formatting • INTL.NumberFormat - Number formatting • INTL.Collator (sorting)
  • 7.
    ECMA-402: Locale • Accept-Languagestandard: IETF (en_US) • Scripts (zh-Hans, zh-Hant, sr-Cyrl, sr-Latn, etc) • Unicode extensions: ja-JP-u-ca-japanese
  • 8.
    How to useINTL Step 0: Getting the user’s locale Sadly, there is no defined API. navigator.language (chrome/FF) and navigator.browserLanguage in IE, or read the Accept-Language header. I prefer to make an intelligent guess, then ask the user — have it preselected. Store locale (string, e.g. “en_US”) a cookie that is independent of your session cookie.
  • 9.
    Localizing Dates new Intl.DateTimeFormat(“es”, {month:"long"}).format(d) 'Febrero' newIntl.DateTimeFormat("es", {month:"long",day:"numeric"}).format(d) '11 de febrero’ ** Use an empty array as the first argument to use the user’s default (browser) locale. May not be correct, however.
  • 10.
    Numbers!! > new Intl.NumberFormat(“en-US").format(1234.5678); '1,234.568' >new Intl.NumberFormat("de").format(1234.5678); '1.234,568' > new Intl.NumberFormat("fr").format(1234.5678); '1 234,568' > new Intl.NumberFormat("en-US",{style:"percent"}) .format(.023); '2.3%'
  • 11.
    Collation var coll =new Intl.Collator(['en'], { sensitivity: 'base', ignorePunctuation: true }); base = a = á, etc. coll.compare('Bluebird', ‘bluebird') === 0, case is ignored. coll.compare(‘blackbird’, ‘black-bird’) === 0, punctuation ignored coll.compare('bluebird', ‘blackbird') === 1, (“u” is after “a”)
  • 12.
    What about strings? Somethingold, something new: gettext • It works • Handles pluralization and positional interpolation • Use the existing ecosystem of tools, translation providers • Template-system, framework agnostic
  • 13.
    An example app •https://github.com/jleppert/rosetajs/ • Using Dust, Jed, po2json, browserify • Same workflow client or server • Same message format, code, helpers.
  • 14.
    Developer API • The@i18n template helper. • {@i18n singular="Hello, {first_name}, you have one message." plural="Hello, {first_name}, you have {message_count} messages!" value=“{message_count}"/} • API: i18n.translate(‘Hello, {first_name}, you have a new message!!.’, { first_name: ‘johnathan’});
  • 15.
    How does itwork? • Template files and javascript source are read, an AST is constructed and the @i18n helper calls/API are used to create a .po file. • xgettext - extracts translatable strings. I wrote a version that understands javascript and dust templates, but you can do so for most any language. • po files are sent to translators, where they translate the messages/re-arrange placeholders, etc. • The right po file is selected based upon the user’s selected locate and used during template helper/translation API
  • 16.
    Let’s see itwork http://localhost:8000
  • 17.
    Considerations • Organize templatesby feature (hopefully…) • Automated tar of po files, send to translators via CI system • Translate by feature: “this feature is available in english, french, and spanish will be launched 6/10” • Suffix files by locale for easy organization and co-locate them • Check files into some source control project: receive translations out of order from deployment • Consider adopting a pirate-speak locale — getttext project has many such manglers for po files
  • 18.
    Thanks, and here’ssome More info • Mailing List: http://jsi18n.com • Gettext Overview: https://developer.mozilla.org/en- US/docs/gettext • PO/POT Format: http://pology.nedohodnik.net/doc/user/en_US/ch- poformat.html • JS Gettext Implementation: http://slexaxton.github.io/Jed/ • po2json: https://github.com/mikeedwards/po2json

Editor's Notes

  • #3 solving this problem many times isn’t a sexy problem, but very important for the company developer systems, processes: good, bad and ugly calltech to teleperformance, traffic increases as more people can actually read and interact with the app in their language: step 0 in personalization airware, drones aren’t legal in us, so the app needs to be international from the start rethinking things to ease roll-out, new languages, process, translation quality.
  • #4 everybody loves standards, when they do……come INTL standards Example app, can use everything as is, or just use the concepts
  • #5 more users is obvious, more users === more money for most people german: “my profile” = 32 characters. tabs will fall off the page airplane analogy
  • #6 lots of people use keys. keys. LONG keys. short keys. bad keys. positional? what’s that? plural? we only got one.
  • #7 started work in 2012. embarrassing. CLDR - big tech companies unite. lots of data. locale data.
  • #8 locale, region
  • #9 they forgot this part of the standard. step 0. yeah.
  • #13 translators may need to re-arrange placeholders it’s a PROCESS
  • #14 buzzword alert: isomorphic. i love that word. why i like dust: streams, compiling, fast. AST.
  • #15 introducing
  • #17 demo poedit change stuff, see if it works