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.