Skip to content

Lab 24: Internationalization (i18n)

album-wholesale-v17-signal-pre-jest

In this lab you will add multi-language support to the album wholesale app using Angular’s built-in i18n system. You will mark strings for translation, extract an XLIFF message file, provide a French translation, and build a localized bundle.

Add the i18n attribute to text elements:

<!-- Simple text -->
<h1 i18n="@@app.title">Album Store</h1>
<!-- With description for translators -->
<p i18n="Album count|Shows the number of albums@@album.count">
Available albums
</p>
<!-- Attribute translation -->
<input
type="search"
i18n-placeholder="@@search.placeholder"
placeholder="Search albums…"
/>
<!-- Button -->
<button i18n="@@cart.add">Add to cart</button>

Mark at least 5 strings across the app.

In angular.json, add i18n configuration:

{
"projects": {
"album-wholesale": {
"i18n": {
"sourceLocale": "en-US",
"locales": {
"fr": {
"translation": "src/locale/messages.fr.xlf"
}
}
}
}
}
}
Terminal window
ng extract-i18n --format xlf2 --output-path src/locale

This generates src/locale/messages.xlf. Open the file — you will see each marked string as a <trans-unit>.

Copy the source file and rename it:

Terminal window
cp src/locale/messages.xlf src/locale/messages.fr.xlf

Open messages.fr.xlf and add <target> elements for each unit:

<trans-unit id="app.title" datatype="html">
<source>Album Store</source>
<target>Boutique d'Albums</target>
</trans-unit>
<trans-unit id="cart.add" datatype="html">
<source>Add to cart</source>
<target>Ajouter au panier</target>
</trans-unit>
<trans-unit id="search.placeholder" datatype="html">
<source>Search albums…</source>
<target>Rechercher des albums…</target>
</trans-unit>

Translate all extracted units.

<!-- Plural -->
<p i18n="@@cart.items">
{itemCount, plural,
=0 {No items in cart}
=1 {1 item in cart}
other {{{itemCount}} items in cart}
}
</p>
<!-- Select (gender or category) -->
<span i18n="@@album.type">
{albumType, select,
vinyl {Vinyl record}
cd {Compact disc}
other {Digital}
}
</span>

Add French translations for these expressions in messages.fr.xlf:

<trans-unit id="cart.items" datatype="html">
<source>
{itemCount, plural,
=0 {No items in cart}
=1 {1 item in cart}
other {{{itemCount}} items in cart}
}
</source>
<target>
{itemCount, plural,
=0 {Aucun article}
=1 {1 article}
other {{{itemCount}} articles}
}
</target>
</trans-unit>

Configure the build target in angular.json:

"build": {
"configurations": {
"fr": {
"localize": ["fr"]
},
"production": {
"localize": true
}
}
}

Build all locales:

Terminal window
ng build --localize

Inspect the dist/ folder — you should see browser/en-US/ and browser/fr/ subdirectories.

Serve the French build locally:

Terminal window
cd dist/album-wholesale/browser/fr
npx http-server -p 8080

Open http://localhost:8080 and verify all marked strings appear in French.