Runtime i18n with ivy

Angular Connect 2018

Olivier Combe

@ocombe

Internationalization (i18n)

  • Can be crucial
  • Takes time
  • Should be easier

I18n today: Quick recap

  • Add “i18n” attribute
  • Use “i18n-” attributes
  • Use ICU expressions

Updated {

minutes,

plural,

=0 {just <b>now</b>}

=1 {one minute ago}

other {{{minutes}} minutes ago}

}

I18n today: Quick recap

  • Add “i18n” attribute
  • Use “i18n-” attributes
  • Use ICU expressions


  • Extract & translate
  • Merge at build time

Loading
translations

Templates

Serializer

I18n Nodes

HTML Nodes

HTML Parser

Build

AOT Compiler

Factories

Merge

Bootstrap

View creation

Templates

Serializer

I18n Defs

HTML Nodes

HTML Parser

AOT Compiler

Definitions

Bootstrap

View creation

Build

Runtime or Build

Loading
translations

<div title="Header">
<span>Hello {{name}}</span>
</div>

<div i18n i18n-title title="Header">
<span>Hello {{name}}</span>
</div>

template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
elementStart
(0, 'div', ['title', 'Header']);
elementStart
(1,'span');
text
(2);
elementEnd
();
elementEnd
();
}
if (rf & RenderFlags.Update) {

textBinding(2, interpolation1("Hello ", ctx.name, ""));
}
}

template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
elementStart
(0, 'div');
element
(1,'span');

elementEnd();
}
if (rf & RenderFlags.Update) {
}
}

template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
elementStart
(0, 'div');

i18nAttributes(1, MSG_DIV_0_ATTR);

i18nStart(2, MSG_DIV_0);
element(3,'span');
i18nEnd();
elementEnd();
}
if (rf & RenderFlags.Update) {

i18nExp(bind(ctx.name));

i18nApply(2);
}
}

['title', 'Header']

`�#3� Hello �0� �/#3�`

template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
elementStart
(0, 'div', ['title', 'header']);
elementStart
(1,'span');
text
(2);
elementEnd
();
elementEnd
();
}
if (rf & RenderFlags.Update) {

textBinding(2, interpolation1("Hello ", ctx.name, ""));
}
}

template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
elementStart
(0, 'div');

i18nAttributes(1, MSG_DIV_0_ATTR_1);

i18nStart(2, MSG_DIV_0);
element(3,'span');
i18nEnd();
elementEnd();
}
if (rf & RenderFlags.Update) {

i18nExp(bind(ctx.name));

i18nApply(2);
}
}

@synalx

  • Cannot change nesting
  • Cannot duplicate placeholders
  • Cannot use directives/components in ICU expressions

Limitations

Benefits

Drawbacks

  • Lazy-loading is possible
    • 1 bundle for all languages
  • Support for libraries

Limitations

Benefits

Drawbacks

  • Small overhead at 1st template creation
  • If lazy loading: loading time

Limitations

Benefits

Drawbacks

And next ?

WARNING

Everything beyond this slide is still theoretical

Runtime service

template: (rf: RenderFlags, ctx: MyApp) => {
if (rf & RenderFlags.Create) {
elementStart
(0, 'div');

i18nAttributes(1, MSG_DIV_0_ATTR);

i18nStart(2, MSG_DIV_0);
element(3,'span');
i18nEnd();
elementEnd();
}
if (rf & RenderFlags.Update) {

i18nExp(bind(ctx.name));

i18nApply(2);
}
}

['title', 'Header']

`�#2� Hello �0� �/#2�`

Remember when I showed you this? Where does “MSG_DIV” comes from?

let MSG_DIV_0: string;
if (IS_CLOSURE) {
MSG_DIV_0 = goog.getMsg(...);
} else {
MSG_DIV_0 = i18nService(...);
}

i18nService is a placeholder name, we haven’t decided what the name will be

I18n Defs

Translations

Service

Serializer

Serializer: XLF, XTB, ..?

Runtime service

  • Usable everywhere
  • Tree-shakeable
  • Supports lazy-loading
  • Support multiple locales
  • Fully functional without compilation

Thanks!

Olivier Combe
@ocombe

Runtime i18n with Ivy - Google Slides