Skip to content

Instantly share code, notes, and snippets.

@stasm
Last active August 29, 2015 14:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stasm/c99010a8ab6d467562ba to your computer and use it in GitHub Desktop.
Save stasm/c99010a8ab6d467562ba to your computer and use it in GitHub Desktop.
New syntax for L20n

New Syntax Proposal for L20n

Goals & Means:

  • Make the most commonly used syntax easy on the eyes by reducing the number of characters used.

    <hello "Hello, {{ $user.name }}!">
    { hello "Hello, { user.name }!" }
  • Improve error recovery and make it easier to use HTML in translations by using an entity delimiter which is already considered special.

    <welcome "Welcome to <em>L20n</em>.">
     { welcome "Welcome to <em>L20n</em>." }
  • Make it easy to parse complex expressions by building on the Lisp syntax.
    This also allows to use dashes in entity names.

    <currentTime "It's {{ $intl.datetime(date) }} right now">
    { current-time "It's { (intl-time date) } right now" }
  • Make it possilbe to reference entities by dynamic names by reusing the S-expression idiom.

    (entity "hello")
  • Make it clearer that translation variants are different permutations of the same translation data and as such, they are different than attributes and are not part of the social contract. Use a different accessor syntax than the one used for entity attributes and arguments hierarchies.

    hello.feminine     // a variant of translation
    hello::ariaLabel   // entity data 
    $user.name         // app data
    :hello#feminine    // a variant of translation
    :hello.ariaLabel   // entity data 
    user.name          // app data
; comments start with ;
; identifier begin with a non-numeric character and can contain alphanumeric
; characters and !, -, _, and ?
; by convention, identifiers starting with - denote private entities
{ hello-world "Hello, world!" }
{ -private "This is a private entity" }
; placeables are expressions defined inside of {}
; references to other entities start with :
; developer-provided args are symbols in the gloal scope
; javadoc can be used to mark up entities and macros with more information
{ hello-world "Hello, { :world }!" }
; @param username The name of the user.
{ welcome "Welcome, { username }." }
; expressions are S-expressions (callee arg1 arg2)
; functions provided by the library can only appear as callees
; (it's not possible to pass them by reference into other forms)
; but not all callees are library functions; see macros
; @param date The date to be formatted
{ current-time "It's { (intl-time date) } right now" }
; entity and args references are shorthand for the entity and arg forms
{ hello-world "Hello, { (entity "world") }!" }
{ welcome "Welcome, { (arg "username") }." }
; attributes are defined with the same grammar as entity values
; attribute names follow the symbol syntax
; value is not mandatory
{ i-have-attrs "Value"
public "Public attribute"
-private "Private attribute" }
{ send-sms aria-label "Send SMS" }
; attributes are accessed with . or with the (attr …) form
; properties of developer-provided args use the same syntax
{ ref-public "This is { :i-have-attrs.public}" }
{ ref-private "This is { :i-have-attrs.-private}" }
{ welcome "Welcome, { user.firstname }." }
{ ref-public "This is { (attr :i-have-attrs "public") }" }
{ ref-private "This is { (attr :i-have-attrs "private") }" }
{ welcome "Welcome, { (attr user "firstname") }." }
; index is defined in []
; hashes are defined as series of hash pairs {}
; the default hash pair is marked with {* }
; hash keys are symbols or strings
; @param n Number of notifications
{ notifications [(plural n)]
{* one "{ n } notification"}
{many "{ n } notifications"}
{"two words" "{ n } notifications"}}
; hash variants are accessed wih # or with the (variant …) form
{ one-notification "{ :notifications#one }" }
{ one-notification "{ (variant :notifications "one") }" }
; commas are treated as whitespace but can improve readability
; @param n Number of notifications
; @param gender The gender of the user
{ notifications [(plural n), gender]
{* one "{ n } notification"}
{many
{* feminine "She sent { n } notifications"}
{masculine "He sent { n } notifications"}}}
{ many-feminine-notifications "{ :notifications#many#feminine }" }
; macros are defined with a Lisp-like syntax
; they are referenced like entities using the : prefix
; the following symbols are supported for now
; entity attr variant defmacro import cond
; true false not and or + - * / mod max min = < > <= >=
; library symbols which are not callees must be prefixed by &
; @param x The number to choose the plural form for.
; @return One of pre-defined plural form names.
; @values "one" "many"
(defmacro plural [x]
(cond
(= x 1) "one"
&true "many"))
; @param n Number of notifications
{ messages [(:plural n)]
{* one "{ n } notification"}
{many "{ n } notifications"}}
(defmacro between [n start end]
(and
(<= start n)
(<= n end)))
(defmacro polish-plural [n]
(cond
(= n 1) "one"
(and
(:between (mod n 10) 2 4)
(not (:between (mod n 100) 12 14))) "few"
(or
(:between (mod n 10) 0 1)
(:between (mod n 10) 5 9)
(:between (mod n 100) 12 14) "many")
&true "other"))
<between($n, $start, $end) {
$start <= $n && $n <= $end ?
'true' : 'false'
}>
<polishPlural($n) {
$n == 1 ?
'one' :
(between($n % 10, 2, 4) == 'true' &&
between($n % 100, 12, 14) == 'false') ?
'few' :
(between($n % 10, 0, 1) == 'true' ||
between($n % 10, 5, 9) == 'true' ||
between($n % 100, 12, 14) == 'true') ?
'many' :
'other'
}>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment