# The *UX* of Language
### It are very importants.
# *Briefly*
There's a lot of pressure for someone who is talking on *The UX of Language* to speak eloquently.
There is also often a misconception that I can speak multiple languages.   I assure you   *No Conozco Pantelones Verdes*
Let's call me an *enabler* of those people who can speak with grace and restraint. *;)*
## This is less about *internationalization* ## and more about *user experience*.
## Anytime you rely on data to output a *message* ## you'll want to consider these problems.
## Thing(s) about *Alex* alex sexton
I *like* to build JavaScript programs
My mom was an english teacher   (I think)
8 inch vertical jump   *Bench* 115 lbs *Squat* 250 lbs
Tweet: Web programming is the science of coming up with increasingly complicated ways of concatenating strings.
# A Brief History of # *String Concatenation*
# 1986   Static text files ruled the web.
# Some time passes
People desire to *customize content* based on the person on the page
Enter the era of ## *Literally Just* ## *Outputting Concatenated Strings*
# 1993 : CGI-BIN
#!/usr/bin/perl

print "Content-type:text/html\r\n\r\n";
print '<html>';
print '<head>';
print '<title>Hello Word - First CGI Program</title>';
print '</head>';
print '<body>';
print '<h2>Hello '
print $USERNAME;
print '! This is my 1st CGI app!</h2>';
print '</body>';
print '</html>';
 
1;
Enter the era of *Crappy Templates* that have enough logic to make things work.
# 1995
<?php if ( isset($GET['USER'] ) { ?>
                Welcome <?= $GET['USER']; ?>!
            <?php
            }
            ?>
            
  *PHP* (Personal Home Page) is released.
Nearly 10 Years of ## *The String Concatenation* # *Dark Ages*
# 2004-Present
var data = model.get('user');
            render(userTemplate(data));
            
  *MVC Frameworks* promote data/presentation decoupling   *Logicless templates* come into popularity
## So we can finally render # *HTML*
## What about rendering a sentence?
# A Templated Sentence
// Handlebars template
          Welcome to the site, {{user_name}}!
          
  ## Seems *good*!
## Let's try another.
# Another Templated Sentence
// Handlebars template
          Hi {{user_name}}, you have {{msg_count}} new messages!
          
  ## Seems *good*?!?!
# *nope.*
## Hi *Alex*, you have *1* new messages!
## *gross.*
# The *UX* of Language
Our traditional way of concatenating strings together is *not sufficient* when those strings form a sentence.
## *POLL* Do the visitors of your site care more about well-formed markup or well-formed sentences?
## We can do *better*
## Consider the previous example *>* You have 2 new messages.
## What about? You have X new message(s). Messages you have: 2
# lol*no*
## Plural Branching  
if (num === 1) {
            return 'You have 1 new message.';
          }
          else {
            return 'You have ' + num + ' new messages.';
          }
          
## Let's add spanish...
if (lang == 'en') {
            if (num === 1) {
              return 'You have 1 new message.';
            }
            else {
              return 'You have ' + num + ' new messages.';
            }
          }
          else if (lang == 'es') {
            if (num === 1) {
              // close enough
              return 'Tienes una message nueva.';
            }
            else {
              return 'Tienes ' + num + ' messages nuevas.';
            }
          }
          
## Pretty ugly, and coupled ## directly into your _app_ code.
## *plus* ## consider these commonly ## supported languages

am  bn  cs  de  es  fa  fr  gsw hi  id  it kn

ln mk mr nl pl ru sl sv te tr vi ar
br cy el et fi ga gu hr in iw ko lt
ml ms no pt shi sq sw th uk zh bg ca
da en eu fil gl he hu is ja lag lv mo
mt or ro sk sr ta tl ur

Where's your

## *if-statement-pluralization* # *God* ## Now?!
## I know what you're thinking
## Richard Stallman hath fought ## the i18n ninjas and bestoweth ## *GNU Gettext* among us.
![img/stallman.png](img/stallman.png)
## I thought so too.
## Navigating the ## *Message* Landscape
# *properties files*
## Usually just for i18n ### (if you can call it that)
## Key Value Pairs
var properties_en = {
              "button_text" : "Submit",
              "invalid_msg" : "Please try again."
            };
             
            var properties_es = {
              "button_text" : "Submitar",
              "invalid_msg" : "Por favor, trya againo"
            };
            
## Use keys in templates instead of english  
<form>
             <input value="{{properties.button_text}}" name="s1" />
             <span class="hidden">{{properties.invalid_msg}}<span>
            </form>
            
## *Common everywhere* ## (Java/Spring, Rails, etc)
## Doesn't really address any of the hard ## problems except rendering different ## strings for different locales
## Lots of time they'll add ## *`sprintf`*
## Properties + Interpolation    
var properties_en = {
              "msg_count" : "You have %d messages.",
            };
             
            sprintf( properties_en.msg_count, num_msgs );
            
  ## Look *familiar*?
## So we can *switch out* messages ## and we can *interpolate* data into them.
## But they're incorrectly *pluralized* and ## devoid of *gender* or *context* ## (and still more!)
## Not to mention *authoring* templates ## with no messages in view ## starts to suck fast.
# Back to *Stallman*
# Gettext #   ## *Plural Forms* and *PO Files*
## Decouples data and message
## Decouples data and message ## *and some locale specifics*

PO Files (as json, cause .po is uggers)

{
              "locale" : "en_US",
              "plural_form" : function (n) {
                if (n === 1) {
                  return 0;
                }
                return 1;
              },
              "messages" : {
                "There is 1 message." : [
                  "There is 1 message.",
                  "There are %d messages."
                ]
              }
            }
## *Plural Form* Functions   These are executed at runtime to see which of the strings to return.  
var msg = ngettext(
              'There is 1 message',
              'There are %d messages.',
              msg_count
            );
            return sprintf(msg, msg_count);
            
## The *English* Plural Form  
function (n) {
  if (n === 1) {
    return 0;
  }
  return 1;
}
## The *Spanish* Plural Form  
function (n) {
  if (n === 1) {
    return 0;
  }
  return 1;
}
## The *French* Plural Form  
function (n) {
  if (n == 1 || n == 0) {
    return 0;
  }
  return 1;
}
## The *Slovenian* Plural Form
function (n) {
  if ((n % 100) == 1) {
    return 1;
  }
  if ((n % 100) == 2) {
    return 2;
  }
  if ((n % 100) == 3 || (n % 100) == 4) {
    return 3;
  }
  return 0;
}
## Messages as Keys  
My Template
            <h1>Jimmy's Message Notifier</h1>

            <p>{{_ "There is 1 message." "There are %d messages." num_msgs}}</p>
            
## Gettext will *prefix* existing keys with ## your *context*. This can be used for ## differentiating *gender* messages.

Contexts for Gender

{
              "locale" : "en_US",
              "plural_form" : function (n) {
                if (n === 1) { return 1; }
                return 0;
              },
              "messages" : {
                "male*He has 1 message." : [
                  "He has 1 message.",
                  "He has %d messages."
                ],
                "female*He has 1 message." : [
                  "She has 1 message.",
                  "She has %d messages."
                ]
              }
            }
## So, for gender...
pgettext("He liked it", gender);
## Common Mistake
gettext("I like my red ") + gettext('shirt');
## You *cannot ever* rely on being able to ## concatenate two translated strings into ## a *single message*.
## I like my *red* shirt # vs. ## Me gusta mi camisa *roja*
## What do we have now?
## We can *pluralize* our message.
## We can *interpolate* our message.
## We can *pluralize* our message ## correctly for each *locale*.
## We can have templates with messages ## *kind of* in them. At least readably.
## We can use gender specific words as the ## locale requires.
## Gettext seems to do a good job at ## our *core concerns* across locales.
## Interpolation ## Gender ## Pluralization ## Dev Happiness
# That's why I wrote *Jed*
Jed
var i18n = new Jed({ locale_data: { ... } });
 
// Use the chainable API
 
i18n.translate( "There is one translation." )
    .onDomain( "messages" )
    .withContext( "male" )
    .ifPlural( num, "There are %d translations." )
    .fetch( num );
 
// Or kick it old school
 
var out = i18n.dnpgettext(
  "messages",
  "male",
  "There is one translation.",
  "There are %d translations.",
  num
);

Jed.sprintf( out, num );
            
# So what's *wrong* with it?
## Back to *just english*
## There are *3* messages from *2* people.
# *uh oh*
## Gettext cannot handle multiple plurals ## in the same message.
## What if I have a _real_ context?
## *Gettext* can only go one level deep on ## any of its features.
## It has a *C* API
gettext = function(key)
dgettext = function(domain, key)
dcgettext = function(domain, key, category)
ngettext = function(singular, plural, value)
dngettext = function(domain, singular, plural, value)
dcngettext = function(domain, snr, plural, val, cat)
pgettext = function(context, key)
dpgettext = function(domain, context, key)
npgettext = function(context, singular, plural, value)
dnpgettext = function(domain, cnx, sngr, plural, val)
dcnpgettext = function(dom, cnx, sngr, plurl, val, cat)
## Plural Forms are *repeated* each translation
## Even if *one word* changes ## You have to retranslate the ## *whole sentence*
## *Fuzzy* matching is hard in the client
## Not very extensible.
# Thanks *Norbert*
# ICU *MessageFormat*
## MessageFormat ## == ## *PluralFormat* + *SelectFormat*
# PluralFormat ## zero, one, two, few, many, other
## Plural Functions   These are built into the spec, and pulled from [CLDR](http://cldr.unicode.org/)
function ( n ) {
  if ( n === 1 ) {
    return "one";
  }
  return "other";
}           
## The most basic syntax overview
// Text is just text
            Literal
             
            // Wrap named variables in curlies
            Literal {Variable}
             
            // For the formatting functions
            // start with a variable, name the type of formatter
            {Variable, plural||select,
              // List your options
              option1 {literal} // this is recursive at this point
              option2 {literal2 OR anotherMessageFormat}
              option3 {# = Variable}
            }
            

Try this again

You have {NUM_MSG, plural,
                      one {1 message}
                      other {# messages}
                    }.
            
## *+*
{
  "NUM_MSG" : 1
}
## ICU Plural Keywords + Literals
You have {NUM_MSG, plural,
                      =0  {no new messages}
                      one {1 message}
                      other {# messages}
                    }.
            
## *+*
{
              "NUM_MSG" : 1
            }
            
## For those of you who've been saying # "But I *don't need* multiple languages"
## *Try this in just english*     There are 5 results in 2 categories
## *Even better*     He received 5 results in 2 categories

Multiple Plurals

There {NRES, plural, one {is one result}
  other {are # results}
} in {NCAT, plural, one {one category}
  other {# categories}
}.
## *+*
{ "NRES" : 5, "NCAT": 2 }

Select Format

{GEND, select, male {He} female {She} other {They}
} found {NRES, plural, one {one result}
  other {# results}
} in {NCAT, plural, one {one category}
  other {# categories}
}.
## *+*
{ "NRES" : 5, "NCAT": 2, "GEND" : "male" }

Named Args

{THE_ARG} is a named argument.
## *+*
{ "THE_ARG" : "This Argument" }

Plugins

{PERSON} added {PLURAL_NUM_PEOPLE, plural, offset:1
     =0 {no one}
     =1 {just {GENDER, select, male {him} female {her} other{them}}self}
    one {{GENDER, select, male {him} female {her} other{them}}self and one other person}
  other {{GENDER, select, male {him} female {her} other{them}}self and # other people}
} to {GENDER, select,
   male {his}
 female {her}
  other {their}
} group.
## *+*
{ "PERSON" : "Alex", "PLURAL_NUM_PEOPLE" : 2, "GENDER": "male" }
## Translator friendly because all ## variations are translated ## *together*
## *NOT* Translator friendly because ## you pretty much have to be a programmer ## to use the *syntax*
![img/mfjs.png](img/mfjs.png)
## *Compile-able*
## Uses Peg.js ![img/mfpeg.png](img/mfpeg.png)

Outputs JavaScript

{THE_ARG} is a named argument.
## *+*
(new MessageFormat()).precompile()
## Integrates directly into Handlebars*  
<div>
          {{#_ "key"}}
            This is {NUM, plural,
              one {a translated sentence}
            other {multiple translated sentences}
          {{/_}}
          </div>
          
## So what does it all mean?   ![img/doublerainbow.jpg](img/doublerainbow.jpg)
## It is *extremely easy* to just wrap your messages ## with a message formatting wrapper.
## *Even if* you don't have ## any intention of internationalizing.
## *Date* and *Number* formatting are important too ## if you are internationalizing your app.
## There's *no excuse* for sentence(s) like this.
## The language *on* your site is *more* important ## than the markup *in* your site.
# *Treat it that way*
## Question(s)? ### Alex Sexton | @SlexAxton | [alexsexton.com](http://alexsexton.com) [alexsexton.com/talks/uxoflanguage](http://alexsexton.com/talks/uxoflanguage)