L10n строк в приложениях (JavaScript)

image

В рамках изучения нового стандарта наткнулся на Tagged Template Literals, по-русски часто обзывают строковые шаблоны.
За рубежом советуют переименовать в tagged string literals, а Template Literals тем временем в interpolated string literals или просто interpoliterals . Обожаю js тусовку, где халивар начинают даже из-за название фичи :)

Что, куда, зачем


Прежде чем перейдем непосредственно к тому о чем я хотел рассказать исходя из заголовка, пару слов о Template Literals.
Наверняка каждый из вас их уже попробовал:

var text =
`Now is the time for all good men
to come to the aid of their
country!`;

console.log( text );
// Now is the time for all good men
// to come to the aid of their
// country!


Первая их крутость, заключается в том, что текст такого литерала можно писать на нескольких строчках и он сам где надо вставит переход на новую строку.
Конечно же вторая крутость заключается в возможности вставки выражений в литерал, что значительно упрощает построение строк в которые вы хотите вставить какое-либо значение.
До ES6:

var name = "Kyle";

var greeting = "Hello " + name + "!";

console.log( greeting );            // "Hello Kyle!"
console.log( typeof greeting );     // "string"


Решение проблемы с помощью Template Literals:

var name = "Kyle";

var greeting = `Hello ${name}!`;

console.log( greeting );            // "Hello Kyle!"
console.log( typeof greeting );     // "string"


Тут конечно надо заметить, что переиспользовать данный литерал с другим значением нельзя. Поэтому ходят споры об именовании. Куда было бы разумней назвать не используя слово шаблон, а интерполяция, что бы не вводить в заблуждение. Данный литерал подобен Immediately-Invoked Function Expression (IIFE), он сразу же запекается в строку. Поэтому передать его и переиспользовать к сожалению возможности нет:

function foo(str) {
    var name = "foo";
    console.log( str ); //name уже давно в str и str typeof 'string'
}

function bar() {
    var name = "bar";
    foo( `Hello from ${name}!` );
}

var name = "global";

bar(); 


Как я писал выше, вставить в строку можно и результат выражения:

function upper(s) {
    return s.toUpperCase();
}

var who = "reader";

var text =
`A very ${upper( "warm" )} welcome
to all of you ${upper( `${who}s` )}!`;

console.log( text );
// A very WARM welcome
// to all of you READERS!

Tagged Template Literals


А теперь самое интересное, рассмотрим с вами использование Tagged Template Literals:

function foo(strings, ...values) {
    console.log( strings );
    console.log( values );
}

var desc = "awesome";

foo`Everything is ${desc}!`;
// [ "Everything is ", "!"]
// [ "awesome" ]


В данном случае tag foo, своего рода вызов функции без (...). Таким образом, мы можем обработать строку дополнительно.
В качестве аргументов, функция foo получает массив строк, которые были вокруг выражения ${desk}, и собственно сами значения выражений.
С помощью такого сахарного синтаксиса, очень просто представить себе перевод строк:

const greeting = lang`Hello ${ name }!`


Как по мне куда проще нежели — учитывая, что в строке есть динамические данные:

const  greeting  = `${ lang('Hello') } ${ name }!`


Или совсем сносный пример который можно часто увидеть:

const greeting  = lang('Hello') + name + '!';


Так как мы получаем в функции по факту разобранную строку на части, нам придется ее самим собрать, с этим нам поможет reduce:

function lang(strings, ...values) {
    return strings.reduce( function(s,v,idx){
        return s + (idx > 0 ? values[idx-1] : "") + v;
    }, "" );
}


Добавим вызов функции перевода и сделаем пример чуть более читабельным, получив вот такой сниппет:

const lang = l = (strings, ...values) =>
    strings.reduce((prevString, nextString, index) =>
        prevString + (index > 0 ? values[index - 1] : '') + translate(nextString), ''); //Реализация функции translate в ваших руках :)


Использование:

const name = 'Дмитрий';

let greeting = lang`Hello ${ name }, how are you?`;

//Или сокращенный
greeting = l`Hello ${ name }, how are you?`;
//Привет Дмитрий, как дела?


Еще один очень полезный пример перевода чисел в формат US $:

function dollabillsyall(strings, ...values) {
    return strings.reduce( function(s,v,idx){
        if (idx > 0) {
            if (typeof values[idx-1] == "number") {
                // look, also using interpolated
                // string literals!
                s += `$${values[idx-1].toFixed( 2 )}`;
            }
            else {
                s += values[idx-1];
            }
        }

        return s + v;
    }, "" );
}

var amt1 = 11.99,
    amt2 = amt1 * 1.08,
    name = "Kyle";

var text = dollabillsyall
`Thanks for your purchase, ${name}! Your
product cost was ${amt1}, which with tax
comes out to ${amt2}.`

console.log( text );
// Thanks for your purchase, Kyle! Your
// product cost was $11.99, which with tax
// comes out to $12.95.


Собственно говоря у пост обработки строк Tagged Template Literals есть и другие применения, но это уже за рамками темы, пишите в комментариях если есть, что добавить :)
Источник вдохновения:
github.com/getify/You-Dont-Know-JS/blob/master/es6%20%26%20beyond/ch2.md

UPD: спасибо dotme
UPD1: спасибо alip

© Habrahabr.ru