test(core): verify that Ivy i18n works correctly with HTML namespaces (#36943)
This commit adds several tests to verify that i18n logic in Ivy handles elements with HTML namespaces correctly. Related to #36941. PR Close #36943
This commit is contained in:
parent
7acd33007d
commit
7a30153aa1
|
@ -3832,4 +3832,102 @@ $` + String.raw`{$I18N_4$}:ICU:\`;
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('namespaces', () => {
|
||||
it('should handle namespaces inside i18n blocks', () => {
|
||||
const input = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<foreignObject i18n>
|
||||
<xhtml:div xmlns="http://www.w3.org/1999/xhtml">
|
||||
Count: <span>5</span>
|
||||
</xhtml:div>
|
||||
</foreignObject>
|
||||
</svg>
|
||||
`;
|
||||
|
||||
const output = String.raw`
|
||||
var $I18N_0$;
|
||||
if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) {
|
||||
const $MSG_EXTERNAL_7128002169381370313$$APP_SPEC_TS_1$ = goog.getMsg("{$startTagXhtmlDiv} Count: {$startTagXhtmlSpan}5{$closeTagXhtmlSpan}{$closeTagXhtmlDiv}", {
|
||||
"startTagXhtmlDiv": "\uFFFD#3\uFFFD",
|
||||
"startTagXhtmlSpan": "\uFFFD#4\uFFFD",
|
||||
"closeTagXhtmlSpan": "\uFFFD/#4\uFFFD",
|
||||
"closeTagXhtmlDiv": "\uFFFD/#3\uFFFD"
|
||||
});
|
||||
$I18N_0$ = $MSG_EXTERNAL_7128002169381370313$$APP_SPEC_TS_1$;
|
||||
}
|
||||
else {
|
||||
$I18N_0$ = $localize \`$` +
|
||||
String.raw`{"\uFFFD#3\uFFFD"}:START_TAG__XHTML_DIV: Count: $` +
|
||||
String.raw`{"\uFFFD#4\uFFFD"}:START_TAG__XHTML_SPAN:5$` +
|
||||
String.raw`{"\uFFFD/#4\uFFFD"}:CLOSE_TAG__XHTML_SPAN:$` +
|
||||
String.raw`{"\uFFFD/#3\uFFFD"}:CLOSE_TAG__XHTML_DIV:\`;
|
||||
}
|
||||
…
|
||||
function MyComponent_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵnamespaceSVG();
|
||||
$r3$.ɵɵelementStart(0, "svg", 0);
|
||||
$r3$.ɵɵelementStart(1, "foreignObject");
|
||||
$r3$.ɵɵi18nStart(2, $I18N_0$);
|
||||
$r3$.ɵɵnamespaceHTML();
|
||||
$r3$.ɵɵelementStart(3, "div", 1);
|
||||
$r3$.ɵɵelement(4, "span");
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵi18nEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
verify(input, output);
|
||||
});
|
||||
|
||||
it('should handle namespaces on i18n block containers', () => {
|
||||
const input = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<foreignObject>
|
||||
<xhtml:div xmlns="http://www.w3.org/1999/xhtml" i18n>
|
||||
Count: <span>5</span>
|
||||
</xhtml:div>
|
||||
</foreignObject>
|
||||
</svg>
|
||||
`;
|
||||
|
||||
const output = String.raw`
|
||||
var $I18N_0$;
|
||||
if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) {
|
||||
const $MSG_EXTERNAL_7428861019045796010$$APP_SPEC_TS_1$ = goog.getMsg(" Count: {$startTagXhtmlSpan}5{$closeTagXhtmlSpan}", {
|
||||
"startTagXhtmlSpan": "\uFFFD#4\uFFFD",
|
||||
"closeTagXhtmlSpan": "\uFFFD/#4\uFFFD"
|
||||
});
|
||||
$I18N_0$ = $MSG_EXTERNAL_7428861019045796010$$APP_SPEC_TS_1$;
|
||||
}
|
||||
else {
|
||||
$I18N_0$ = $localize \` Count: $` +
|
||||
String.raw`{"\uFFFD#4\uFFFD"}:START_TAG__XHTML_SPAN:5$` +
|
||||
String.raw`{"\uFFFD/#4\uFFFD"}:CLOSE_TAG__XHTML_SPAN:\`;
|
||||
}
|
||||
…
|
||||
function MyComponent_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵnamespaceSVG();
|
||||
$r3$.ɵɵelementStart(0, "svg", 0);
|
||||
$r3$.ɵɵelementStart(1, "foreignObject");
|
||||
$r3$.ɵɵnamespaceHTML();
|
||||
$r3$.ɵɵelementStart(2, "div", 1);
|
||||
$r3$.ɵɵi18nStart(3, $I18N_0$);
|
||||
$r3$.ɵɵelement(4, "span");
|
||||
$r3$.ɵɵi18nEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
verify(input, output, {verbose: true});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,15 +9,15 @@
|
|||
// below. This would normally be done inside the application `polyfills.ts` file.
|
||||
import '@angular/localize/init';
|
||||
|
||||
import {CommonModule, registerLocaleData} from '@angular/common';
|
||||
import {CommonModule, DOCUMENT, registerLocaleData} from '@angular/common';
|
||||
import localeEs from '@angular/common/locales/es';
|
||||
import localeRo from '@angular/common/locales/ro';
|
||||
import {computeMsgId} from '@angular/compiler';
|
||||
import {Component, ContentChild, ContentChildren, Directive, ElementRef, HostBinding, Input, LOCALE_ID, NO_ERRORS_SCHEMA, Pipe, PipeTransform, QueryList, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core';
|
||||
import {Component, ContentChild, ContentChildren, Directive, ElementRef, HostBinding, Input, LOCALE_ID, NO_ERRORS_SCHEMA, Pipe, PipeTransform, QueryList, RendererFactory2, TemplateRef, Type, ViewChild, ViewContainerRef, ɵsetDocument} from '@angular/core';
|
||||
import {setDelayProjection} from '@angular/core/src/render3/instructions/projection';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {clearTranslations, loadTranslations} from '@angular/localize';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {By, ɵDomRendererFactory2 as DomRendererFactory2} from '@angular/platform-browser';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
import {onlyInIvy} from '@angular/private/testing';
|
||||
import {BehaviorSubject} from 'rxjs';
|
||||
|
@ -530,6 +530,75 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('should work correctly with namespaces', () => {
|
||||
beforeEach(() => {
|
||||
function _document(): any {
|
||||
// Tell Ivy about the global document
|
||||
ɵsetDocument(document);
|
||||
return document;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{provide: DOCUMENT, useFactory: _document, deps: []},
|
||||
// TODO(FW-811): switch back to default server renderer (i.e. remove the line below)
|
||||
// once it starts to support Ivy namespace format (URIs) correctly. For now, use
|
||||
// `DomRenderer` that supports Ivy namespace format.
|
||||
{provide: RendererFactory2, useClass: DomRendererFactory2}
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle namespaces inside i18n blocks', () => {
|
||||
loadTranslations({
|
||||
[computeMsgId(
|
||||
'{$START_TAG__XHTML_DIV} Hello ' +
|
||||
'{$START_TAG__XHTML_SPAN}world{$CLOSE_TAG__XHTML_SPAN}{$CLOSE_TAG__XHTML_DIV}')]:
|
||||
'{$START_TAG__XHTML_DIV} Bonjour ' +
|
||||
'{$START_TAG__XHTML_SPAN}monde{$CLOSE_TAG__XHTML_SPAN}{$CLOSE_TAG__XHTML_DIV}'
|
||||
});
|
||||
|
||||
const fixture = initWithTemplate(AppComp, `
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<foreignObject i18n>
|
||||
<xhtml:div xmlns="http://www.w3.org/1999/xhtml">
|
||||
Hello <span>world</span>
|
||||
</xhtml:div>
|
||||
</foreignObject>
|
||||
</svg>
|
||||
`);
|
||||
|
||||
const element = fixture.nativeElement;
|
||||
expect(element.textContent.trim()).toBe('Bonjour monde');
|
||||
expect(element.querySelector('svg').namespaceURI).toBe('http://www.w3.org/2000/svg');
|
||||
expect(element.querySelector('div').namespaceURI).toBe('http://www.w3.org/1999/xhtml');
|
||||
expect(element.querySelector('span').namespaceURI).toBe('http://www.w3.org/1999/xhtml');
|
||||
});
|
||||
|
||||
it('should handle namespaces on i18n block containers', () => {
|
||||
loadTranslations({
|
||||
[computeMsgId(' Hello {$START_TAG__XHTML_SPAN}world{$CLOSE_TAG__XHTML_SPAN}')]:
|
||||
' Bonjour {$START_TAG__XHTML_SPAN}monde{$CLOSE_TAG__XHTML_SPAN}'
|
||||
});
|
||||
|
||||
const fixture = initWithTemplate(AppComp, `
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<foreignObject>
|
||||
<xhtml:div xmlns="http://www.w3.org/1999/xhtml" i18n>
|
||||
Hello <span>world</span>
|
||||
</xhtml:div>
|
||||
</foreignObject>
|
||||
</svg>
|
||||
`);
|
||||
|
||||
const element = fixture.nativeElement;
|
||||
expect(element.textContent.trim()).toBe('Bonjour monde');
|
||||
expect(element.querySelector('svg').namespaceURI).toBe('http://www.w3.org/2000/svg');
|
||||
expect(element.querySelector('div').namespaceURI).toBe('http://www.w3.org/1999/xhtml');
|
||||
expect(element.querySelector('span').namespaceURI).toBe('http://www.w3.org/1999/xhtml');
|
||||
});
|
||||
});
|
||||
|
||||
describe('should support ICU expressions', () => {
|
||||
it('with no root node', () => {
|
||||
loadTranslations({
|
||||
|
|
Loading…
Reference in New Issue