Skip to main content

Lab 24: Internationalization (i18n)

πŸ“– Resources​

πŸš€ Starter Code​

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.

πŸ“ Instructions​

Step 1: Mark Strings in Templates​

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.

Step 2: Configure the Source Locale​

In angular.json, add i18n configuration:

{
"projects": {
"album-wholesale": {
"i18n": {
"sourceLocale": "en-US",
"locales": {
"fr": {
"translation": "src/locale/messages.fr.xlf"
}
}
}
}
}
}

Step 3: Extract the Message File​

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>.

Step 4: Create the French Translation​

Copy the source file and rename it:

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.

Step 5: Use Plural and Select Expressions​

<!-- 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>

Step 6: Build with Localization​

Configure the build target in angular.json:

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

Build all locales:

ng build --localize

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

Step 7: Serve and Verify​

Serve the French build locally:

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

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