Pull to refresh

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

Reading time 4 min
Views 15K
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

UPD2: спасибо frol
Кроме того, часто нужен контекст (чтобы «name» в одних случаях переводилось как «имя», а в других — «наименование»), где можно было бы добавить в том числе и внешнюю информацию (пол {М/Ж}, число {единственное/множественное}, и тд и тп).

Интересное замечание по поводу более продвинутого перевода. В целом в статье я попытался показать именно сахар, а не способы и подходы перевода, но кое-что все же забыл упомянуть:
function bar() {
    return function foo(strings, ...values) {
        console.log( strings );
        console.log( values );
    }
}

const desc = 'OK';
bar()`Everything is ${desc}!`;

Тегом может быть выражение которое возвращает функцию. Благодаря этому возможно передать какие-либо дополнительные аргументы:
lang('ru')`Everything is ${desc}!`;
//
lang('name', 'number')`${name}'s team is about ${count}`;
Tags:
Hubs:
+13
Comments 9
Comments Comments 9

Articles