{"id":6296,"date":"2025-04-28T06:07:00","date_gmt":"2025-04-28T06:07:00","guid":{"rendered":"https:\/\/poeditor.com\/blog\/?p=6296"},"modified":"2026-04-20T12:51:17","modified_gmt":"2026-04-20T12:51:17","slug":"angular-internationalization-localization","status":"publish","type":"post","link":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/","title":{"rendered":"Angular internationalization and localization: A complete guide"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"827\" src=\"https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization-1024x827.png\" alt=\"angular internationalization and localization\" class=\"wp-image-6314\" srcset=\"https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization-1024x827.png 1024w, https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization-300x242.png 300w, https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization-768x620.png 768w, https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization-1536x1240.png 1536w, https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization.png 1603w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Angular is a frontend JavaScript framework built for creating large, maintainable web applications. But out of the box, you\u2019re only able to display content in one language \u2014 whatever text you hardcode into your templates.<\/p>\n\n\n\n<p>If you&#8217;re building something for a global audience, or just want your app to support multiple languages, you&#8217;ll need to set up <a href=\"\/blog\/localization-vs-internationalization\/\">localization and internationalization<\/a>.<\/p>\n\n\n\n<p>You may ask: what do those even mean?<\/p>\n\n\n\n<p>In plain terms, internationalization is the process of preparing your app to support different languages and regional settings. Localization, on the other hand, is the actual implementation \u2014 translating your content and formatting things like dates, numbers, and currencies to match the user\u2019s language.<\/p>\n\n\n\n<p>In this guide, we\u2019ll walk through Angular internationalization and localization step by step. You\u2019ll learn how to mark text for translation in your Angular app, handle pluralization and dynamic values, generate translation files, and build separate language versions of the app.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Getting started<\/h2>\n\n\n\n<p>Before we do anything fancy, it\u2019s assumed you already have an Angular application you want to work with \u2014 or at least some basic understanding of how Angular works. So we\u2019ll skip things like setting up components or modules.<\/p>\n\n\n\n<p>But just in case you don\u2019t have a project yet, here\u2019s how to spin one up:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># install Angular CLI\nnpm install -g @angular\/cli\n\n# create a new Angular project\nng new angular-i18n-demo\n\n# navigate into the folder and serve the project\ncd angular-i18n-demo &amp;&amp; ng serve\n<\/code><\/pre>\n\n\n\n<p>Once that&#8217;s running, open <code>src\/app\/app.component.html<\/code> and replace everything with this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;div class=\"container\"&gt;\n  &lt;h1&gt;Welcome to MyApp&lt;\/h1&gt;\n  &lt;p&gt;This is a simple localized Angular app.&lt;\/p&gt;\n\n  &lt;h2&gt;Ongoing Tasks&lt;\/h2&gt;\n  &lt;p&gt;You have {{ tasksCount }} tasks.&lt;\/p&gt;\n&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p>Then in <code>src\/app\/app.component.ts<\/code>, add the <code>tasksCount<\/code> variable:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export class AppComponent {\n  tasksCount = 3;\n}<\/code><\/pre>\n\n\n\n<p>You now have a basic UI with some text we\u2019ll localize in the next steps.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Installing the localization package<\/h2>\n\n\n\n<p>Angular doesn\u2019t include localization support by default \u2014 you have to add it yourself. Fortunately, the Angular team provides an <a href=\"https:\/\/v17.angular.io\/api\/localize\" rel=\"nofollow\">official package<\/a>.<\/p>\n\n\n\n<p>To install it, run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ng add @angular\/localize<\/code><\/pre>\n\n\n\n<p>This installs the package and adds the <a href=\"https:\/\/v17.angular.io\/api\/localize\/init\" rel=\"nofollow\">required import<\/a> to your polyfills file, so Angular knows to use the localization system during builds.<\/p>\n\n\n\n<p>That\u2019s it. You don\u2019t have to import anything manually or write any special code to use it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Marking text for translation<\/h2>\n\n\n\n<p>Now that localization is set up, the next step is to mark the text in your templates that you want Angular to translate.<\/p>\n\n\n\n<p>Angular doesn\u2019t automatically translate anything. You have to tell it: \u201cThis string should be translated.\u201d You do that using the <code>i18n<\/code> attribute.<\/p>\n\n\n\n<p>Here\u2019s an example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;h1 i18n&gt;Welcome to MyApp&lt;\/h1&gt;<\/code><\/pre>\n\n\n\n<p>That <code>i18n<\/code> attribute won\u2019t show up in the rendered page, but when you extract translations, Angular will include that line in the output file. If you go ahead to extract translation stirring this way, Angular will generate some hash-looking values as the custom ID to serve as a unique identifier:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;trans-unit id=\"6273847362193874621\" datatype=\"html\"&gt;\n  &lt;source&gt;Welcome to MyApp&lt;\/source&gt;\n&lt;\/trans-unit&gt;<\/code><\/pre>\n\n\n\n<p>That\u2019s fine for simple apps, but not great when working with external translation tools like <a href=\"https:\/\/poeditor.com\/\">POEditor<\/a> \u2014 because those tools rely on stable IDs to track changes, reuse strings, and sync across teams.<\/p>\n\n\n\n<p>You can avoid that by assigning your own stable ID using the <code>@@<\/code> syntax:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;h1 i18n=\"@@pageTitle\"&gt;Welcome to MyApp&lt;\/h1&gt;<\/code><\/pre>\n\n\n\n<p>This gives you predictable output:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;trans-unit id=\"pageTitle\" datatype=\"html\"&gt;\n  &lt;source&gt;Welcome to MyApp&lt;\/source&gt;\n&lt;\/trans-unit&gt;<\/code><\/pre>\n\n\n\n<p>You can also add a description to help translators understand what a string means \u2014 especially when the text is generic (like \u201cStart\u201d or \u201cSubmit\u201d).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p i18n=\"Intro text shown under the heading\"&gt;\n  This is a simple localized Angular app.\n&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>Angular still generates the ID automatically in this case, but the note gets added. You can combine both a custom ID and a description this way:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p i18n=\"Intro message shown under the heading@@introText\"&gt;\n  This is a simple localized Angular app.\n&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>Now you get both:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;trans-unit id=\"introText\" datatype=\"html\"&gt;\n  &lt;source&gt;This is a simple localized Angular app.&lt;\/source&gt;\n  &lt;note priority=\"1\" from=\"description\"&gt;Intro message shown under the heading&lt;\/note&gt;\n&lt;\/trans-unit&gt;<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Extracting translation strings<\/h2>\n\n\n\n<p>Once you&#8217;ve marked your text with the <code>i18n<\/code> attribute, the next step is to extract those strings into a translation file that Angular or a translator can work with.<\/p>\n\n\n\n<p>By default, when you run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ng extract-i18n<\/code><\/pre>\n\n\n\n<p>Angular creates a file called <code>messages.xlf<\/code> in the root of your project. But you&#8217;re not locked into <code>.xlf<\/code> if that doesn&#8217;t work for your team or translation workflow. You can specify a different format, filename, and output path using flags.<\/p>\n\n\n\n<p>Here are the main options:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Option<\/th><th>What it does<\/th><\/tr><\/thead><tbody><tr><td><code>--format<\/code><\/td><td>Sets the file format. Angular supports <code>xlf<\/code>, <code>xlf2<\/code>, <code>xmb<\/code>, <code>json<\/code><\/td><\/tr><tr><td><code>--out-file<\/code><\/td><td>Changes the name of the file<\/td><\/tr><tr><td><code>--output-path<\/code><\/td><td>Sets the folder where the file is saved<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>For example, you can extract as JSON to a custom folder:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ng extract-i18n --format json --out-file strings.en.json --output-path src\/i18n<\/code><\/pre>\n\n\n\n<p>This will generate:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>src\/i18n\/strings.en.json<\/code><\/pre>\n\n\n\n<p>The content of the file will still depend on what you&#8217;ve marked with<code> i18n<\/code> in your templates, but the structure will be JSON instead of XML.<\/p>\n\n\n\n<p>But for this guide, we\u2019ll stick to using the default format and store translations in the <code>src\/locale<\/code> folder using this command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ng extract-i18n --output-path src\/locale<\/code><\/pre>\n\n\n\n<p>This will create a file called messages.xlf inside the src\/locale folder.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What the .xlf file looks like<\/h3>\n\n\n\n<p>Here\u2019s a simplified example of what you&#8217;ll see:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?xml version=\"1.0\" encoding=\"UTF-8\" ?&gt;\n&lt;xliff version=\"1.2\"&gt;\n  &lt;file source-language=\"en-US\" datatype=\"plaintext\" original=\"ng2.template\"&gt;\n    &lt;body&gt;\n      &lt;trans-unit id=\"introText\" datatype=\"html\"&gt;\n        &lt;source&gt;This is a simple localized Angular app.&lt;\/source&gt;\n        &lt;note priority=\"1\" from=\"description\"&gt;Intro message shown under the heading&lt;\/note&gt;\n      &lt;\/trans-unit&gt;\n    &lt;\/body&gt;\n  &lt;\/file&gt;\n&lt;\/xliff&gt;\n<\/code><\/pre>\n\n\n\n<p>Let\u2019s break that down:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>one string to translate<\/li>\n\n\n\n<li>id=&#8221;introText&#8221; = the custom ID you provided (@@introText)<\/li>\n\n\n\n<li>the actual text from your template<\/li>\n\n\n\n<li>the description you added (if any)<\/li>\n<\/ul>\n\n\n\n<p>You\u2019ll see one <code>trans-unit<\/code> for each piece of marked text in your app.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating translation files for other languages<\/h2>\n\n\n\n<p>Now that you\u2019ve extracted your strings into messages.xlf, the next step is to actually translate them. That file contains your app\u2019s text in English (or whatever your source language is). To support other languages like French or Spanish, you\u2019ll create a copy of that file and translate the contents.<\/p>\n\n\n\n<p>Let\u2019s say you want to add French. Run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cp src\/locale\/messages.xlf src\/locale\/messages.fr.xlf<\/code><\/pre>\n\n\n\n<p>This creates a separate file just for French translations. You can name it anything technically, but it\u2019s a good habit to follow the <code>messages.&lt;lang&gt;.xlf<\/code> naming pattern \u2014 it keeps things tidy, especially as you add more languages.<\/p>\n\n\n\n<p>Next, open <code>messages.fr.xlf<\/code> and look for the blocks. Each one has a <code>&lt;source&gt;<\/code> (your original text) and a space where you can add a <code>&lt;target&gt;<\/code> (your translated text).<\/p>\n\n\n\n<p>Here\u2019s what it looks like before translation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;trans-unit id=\"introText\" datatype=\"html\"&gt;\n  &lt;source&gt;This is a simple localized Angular app.&lt;\/source&gt;\n  &lt;note priority=\"1\" from=\"description\"&gt;Intro message shown under the heading&lt;\/note&gt;\n&lt;\/trans-unit&gt;<\/code><\/pre>\n\n\n\n<p>Update it like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;trans-unit id=\"introText\" datatype=\"html\"&gt;\n  &lt;source&gt;This is a simple localized Angular app.&lt;\/source&gt;\n  &lt;target&gt;Ceci est une application Angular localis\u00e9e.&lt;\/target&gt;\n  &lt;note priority=\"1\" from=\"description\"&gt;Intro message shown under the heading&lt;\/note&gt;\n&lt;\/trans-unit&gt;<\/code><\/pre>\n\n\n\n<p>Repeat that for every <code>trans-unit<\/code> in the file. Be careful not to mess with any of the structure \u2014 don\u2019t delete any tags like <code>&lt;x id=\"INTERPOLATION\"\/&gt;<\/code>, or the build will break. Only update the text inside <code>&lt;target&gt;<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Using POEditor to manage translations<\/h2>\n\n\n\n<p>If you\u2019re working on a real-world app, especially one that supports multiple languages or involves a team \u2014 managing translation files manually can get messy fast. A better approach is to use a translation management platform like POEditor.<\/p>\n\n\n\n<p>With POEditor, you can upload your source translation file (like <code>messages.xlf<\/code>), manage all your strings in a clean web interface, invite translators, and download the updated files when you&#8217;re done.<\/p>\n\n\n\n<p>There are different ways to get your translations in and out of POEditor. The simplest way is to log in to your dashboard, select your project, and import your <code>messages.xlf<\/code> file directly.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXc46VKKhGgX3a7xDc3-Y0ysFdUtaxWf6bs1oDcG6651suLGqn1T3SPV6-wdC7HUxP6NTrhDmOXLxSp2XYd8DcC1dN2ym2h3wRNDFVJNQSgab3SXXLLHERqA-gtTP5i3RfKPzoUN?key=hzdCvloU5ZnzsO_oafvGRN1a\" alt=\"\"\/><\/figure>\n\n\n\n<p>POEditor will detect your keys and source strings, and let you start translating immediately.<\/p>\n\n\n\n<p>If you want to automate your workflow \u2014 say, as part of a CI\/CD pipeline, you can upload your .xlf files programmatically using <a href=\"https:\/\/poeditor.com\/docs\/api\" rel=\"nofollow\">POEditor\u2019s<\/a><a href=\"https:\/\/poeditor.com\/docs\/api\"> <\/a><a href=\"https:\/\/poeditor.com\/docs\/api\" rel=\"nofollow\">API<\/a>.<\/p>\n\n\n\n<p>Here\u2019s a basic example using <code>curl<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -X POST https:\/\/api.poeditor.com\/v2\/projects\/upload \\<br>-F api_token=\"your_api_token\" \\<br>-F id=\"your_project_id\" \\<br>-F updating=\"terms\" \\<br>-F file=@\"src\/locale\/messages.xlf\"<\/code><\/pre>\n\n\n\n<p>There are other optional flags you can use, like <code>overwrite<\/code>, <code>sync_terms<\/code>, or even tagging new and removed keys. See the <a href=\"\/docs\/api#projects_upload\">upload docs<\/a> for everything you can tweak.<\/p>\n\n\n\n<p>Once translations are done, you can use the <a href=\"\/docs\/api#projects_export\">POEditor export API<\/a> to fetch the updated file in your desired format. For Angular, that\u2019s usually <code>xlf<\/code> or <code>xliff_1_2<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>curl -X POST https:\/\/api.poeditor.com\/v2\/projects\/export \\\n-d api_token=\"your_api_token\" \\\n-d id=\"your_project_id\" \\\n-d language=\"fr\" \\\n-d type=\"xlf\"<\/code><\/pre>\n\n\n\n<p>This will return a URL where you can download the French translation file. You can then save that as <code>messages.fr.xlf<\/code> in your project\u2019s <code>src\/locale\/<\/code> folder.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Handling pluralization in Angular (ICU expressions)<\/h2>\n\n\n\n<p>Let\u2019s say you want to display how many tasks a user has. If it&#8217;s 0, you want to show \u201cYou have no tasks.\u201d If it&#8217;s 1, \u201cYou have one task.\u201d If it&#8217;s 3, then \u201cYou have 3 tasks.\u201d<\/p>\n\n\n\n<p>If you just did this in plain HTML, you\u2019d have to write a mess of <code>*ngIf<\/code> blocks to check for each case. But there is a better way with <a href=\"https:\/\/unicode-org.github.io\/icu\/userguide\/locale\/localizing.html\" rel=\"nofollow\">ICU<\/a> (International Components for Unicode) expressions \u2014 a standard way of writing conditional text for things like pluralization, gender, and status.<\/p>\n\n\n\n<p>Here\u2019s how you show task counts in a clean, translation-ready way:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p i18n&gt;\n  {tasksCount, plural,\n    =0 {You have no tasks}\n    =1 {You have one task}\n    other {You have {{ tasksCount }} tasks}\n  }\n&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>Let\u2019s break it down:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>tasksCount is a variable from your component<br>plural is the ICU keyword<\/li>\n\n\n\n<li>0, =1, and other are the rules you\u2019re defining<\/li>\n\n\n\n<li>You can still use interpolation ({{ tasksCount }}) inside the message<\/li>\n<\/ul>\n\n\n\n<p>In your component, you\u2019d just define:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export class AppComponent {\n  tasksCount = 3;\n}<\/code><\/pre>\n\n\n\n<p>When you run <code>ng extract-i18n<\/code>, Angular outputs two things for this ICU expression. The first is a wrapper <code>&lt;trans-unit&gt;<\/code> with your optional ID or description:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;trans-unit id=\"tasksPlural\" datatype=\"html\"&gt;\n  &lt;source&gt;\n    &lt;x id=\"ICU\" equiv-text=\"{tasksCount, plural, =0 {You have no tasks} =1 {You have one task} other {You have {{ tasksCount }} tasks} }\"\/&gt;\n  &lt;\/source&gt;\n  &lt;note priority=\"1\" from=\"description\"&gt;Pluralized task count&lt;\/note&gt;\n&lt;\/trans-unit&gt;<\/code><\/pre>\n\n\n\n<p>A second <code>trans-unit<\/code> with the full ICU logic:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;trans-unit id=\"6482371983123478371\" datatype=\"html\"&gt;\n  &lt;source&gt;{VAR_PLURAL, plural, =0 {You have no tasks} =1 {You have one task} other {You have &lt;x id=\"INTERPOLATION\"\/&gt; tasks}}&lt;\/source&gt;\n&lt;\/trans-unit&gt;<\/code><\/pre>\n\n\n\n<p>Don\u2019t touch the placeholders like <code>&lt;x id=\"INTERPOLATION\"\/&gt;<\/code>. That\u2019s how Angular swaps in the value of <code>tasksCount<\/code> during runtime.<\/p>\n\n\n\n<p>Let\u2019s say you&#8217;re localizing this into French. You\u2019d go into your <code>messages.fr.xlf<\/code> and update the <code>target<\/code> of the ICU expression like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;trans-unit id=\"6482371983123478371\" datatype=\"html\"&gt;\n  &lt;source&gt;{VAR_PLURAL, plural, =0 {You have no tasks} =1 {You have one task} other {You have &lt;x id=\"INTERPOLATION\"\/&gt; tasks}}&lt;\/source&gt;\n  &lt;target&gt;{VAR_PLURAL, plural, =0 {Vous n'avez aucune t\u00e2che} =1 {Vous avez une t\u00e2che} other {Vous avez &lt;x id=\"INTERPOLATION\"\/&gt; t\u00e2ches}}&lt;\/target&gt;\n&lt;\/trans-unit&gt;\n<\/code><\/pre>\n\n\n\n<p>Angular will pick the right message automatically based on the value of <code>tasksCount<\/code>.<\/p>\n\n\n\n<p>You should also know that different languages support different plural rules. For example:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>English: =0, =1, other<\/li>\n\n\n\n<li>Russian: one, few, many, other<\/li>\n\n\n\n<li>Arabic: has six!<\/li>\n<\/ul>\n\n\n\n<p>You can also use category names like <code>zero<\/code>, <code>one<\/code>, <code>few<\/code>, <code>many<\/code>, <code>other<\/code> instead of hardcoded values. Angular follows <a href=\"https:\/\/cldr.unicode.org\/index\/cldr-spec\/plural-rules\" rel=\"nofollow\">CLDR plural rules<\/a> behind the scenes.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{itemCount, plural,\n  zero {No items}\n  one {One item}\n  few {A few items}\n  many {Many items}\n  other {# items}\n}<\/code><\/pre>\n\n\n\n<p>Make sure to only use categories supported by the target language. English, for example, ignores <code>few<\/code> and <code>many<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Formatting dates, numbers, and currency based on locale<\/h2>\n\n\n\n<p>Apart from translating text, internationalization also means displaying values like dates, numbers, percentages, and money in a way that feels familiar to your users.<\/p>\n\n\n\n<p>Angular makes this easy using built-in pipes \u2014 and these pipes are locale-aware. That means they automatically adapt to the active language\/region when you build a localized version of your app.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Date formatting with date pipe<\/h3>\n\n\n\n<p>Say you have a date value:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export class AppComponent {\n  today = new Date();\n}<\/code><\/pre>\n\n\n\n<p>You can display it in your template like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p i18n&gt;The date today is: {{ today | date }}&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>By default, this will follow the formatting of the active locale at build time.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>In English (US): Apr 15, 2025<\/li>\n\n\n\n<li>In French: 15 avr. 2025<\/li>\n<\/ul>\n\n\n\n<p>You can customize the format too:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p i18n&gt;Full date: {{ today | date: 'fullDate' }}&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>Other useful formats: <code>shortDate<\/code>, <code>mediumDate<\/code>,<code> 'yyyy-MM-dd'<\/code>, etc.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Currency formatting with currency pipe<\/h2>\n\n\n\n<p>If you want to show prices or amounts of money:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>price = 1999.5;<\/code><\/pre>\n\n\n\n<p>In your template:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Price: {{ price | currency:'USD' }}<\/code><\/pre>\n\n\n\n<p>In English, this will show as: <code>$1,999.50<\/code>. If you build for French and switch to EUR:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p i18n&gt;Prix : {{ price | currency:'EUR':'symbol' }}&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>This will show: <code>1\u202f999,50 \u20ac<\/code>. Notice how the decimal symbol, currency position, and spacing all change depending on the locale.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Percent and decimal pipes<\/h3>\n\n\n\n<p>In a case where you want to show a percentage, you just have to attach the percent pipe:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p i18n&gt;Completed: {{ completion | percent }}&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>You can also use <code>number<\/code> for decimal formatting:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p i18n&gt;Score: {{ completion | number:'1.1-2' }}&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>This will round and format the number according to the locale.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Translating text inside components<\/h2>\n\n\n\n<p>So far, everything we\u2019ve translated has been inside HTML templates \u2014 which covers most use cases. But sometimes you have strings that live inside your TypeScript code.<\/p>\n\n\n\n<p>Think of toast messages, errors from services, dialog text and anything dynamic that isn\u2019t in the template. For those, Angular gives you the <code>$localize<\/code> function.<\/p>\n\n\n\n<p>It works just like a tagged template literal \u2014 meaning you can write:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const msg = $localize`Some string to translate`;<\/code><\/pre>\n\n\n\n<p>Then Angular will treat that string just like it does with i18n in your templates: it will extract it, let you translate it in your <code>.xlf<\/code> file, and replace it with the correct translation at build time.<\/p>\n\n\n\n<p>Here is a basic usage:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>showSuccess() {\n  this.toastr.success($localize`Changes saved successfully.`);\n}<\/code><\/pre>\n\n\n\n<p>That string will be picked up when you extract translations, just like template content.<\/p>\n\n\n\n<p>You can also insert variables into the translated message:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const username = 'Joe';\nconst message = $localize`Hello, ${username}!`;<\/code><\/pre>\n\n\n\n<p>When Angular extracts this, it adds a placeholder (<code>INTERPOLATION<\/code>) that can be translated separately.<\/p>\n\n\n\n<p>In the <code>.xlf<\/code> file, it\u2019ll show something like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;trans-unit id=\"67238476392834\" datatype=\"html\"&gt;\n  &lt;source&gt;Hello, &lt;x id=\"INTERPOLATION\"\/&gt;!&lt;\/source&gt;\n&lt;\/trans-unit&gt;<\/code><\/pre>\n\n\n\n<p>You can also provide <strong>context<\/strong> or a <strong>custom ID<\/strong> for <code>$localize<\/code>, just like in templates. Here\u2019s how:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const message = $localize`:Shown when the user logs in successfully@@loginSuccess:Welcome back!`;<\/code><\/pre>\n\n\n\n<p>This gives you full control over how the string appears in the .xlf file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Configuring Angular for localization<\/h2>\n\n\n\n<p>At this point, you\u2019ve marked your text using <code>i18n<\/code> and <code>$localize<\/code>, extracted strings into a translation file and translated those strings manually or through a tool like POEditor.<\/p>\n\n\n\n<p>Now it\u2019s time to tell Angular where your translated files live, and what languages your app should support.<\/p>\n\n\n\n<p>This setup happens in one place: your <code>angular.json<\/code> file.<\/p>\n\n\n\n<p>Open your <code>angular.json<\/code> file, and inside the project block (usually under &#8220;projects&#8221; \u2192 &#8220;<code>your-app-name<\/code>&#8220;), add an <code>i18n<\/code> section.<\/p>\n\n\n\n<p>Here\u2019s what it looks like if your app supports English (default) and French:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"i18n\": {\n  \"sourceLocale\": \"en-US\",\n  \"locales\": {\n    \"fr\": {\n      \"translation\": \"src\/locale\/messages.fr.xlf\"\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>Still inside <code>angular.json<\/code>, scroll down to this section:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"architect\" \u2192 \"build\" \u2192 \"options\"\nAdd this line:\n\"localize\": true\nIt should look something like this:\n\"options\": {\n  \"outputPath\": \"dist\/angular-i18n-demo\",\n  \"index\": \"src\/index.html\",\n  \"main\": \"src\/main.ts\",\n  \"polyfills\": &#091;\n    \"zone.js\",\n    \"@angular\/localize\/init\"\n  ],\n  ...\n  \"localize\": true\n}<\/code><\/pre>\n\n\n\n<p>This tells Angular that when it builds the app, generate versions for every language configured.<\/p>\n\n\n\n<p>If you want to serve or test one language at a time using <code>ng serve<\/code>, you\u2019ll need to add per-locale entries under the <code>\"configurations\"<\/code> section.<\/p>\n\n\n\n<p>For example, still inside the <code>\"build\"<\/code> section:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"configurations\": {\n  \"production\": {\n    ...\n  },\n  \"fr\": {\n    \"localize\": &#091;\"fr\"]\n  }\n}\n<\/code><\/pre>\n\n\n\n<p>And under <code>\"serve\"<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\"serve\": {\n  \"builder\": \"@angular-devkit\/build-angular:dev-server\",\n  \"configurations\": {\n    \"development\": {\n      \"buildTarget\": \"your-app-name:build:development\"\n    },\n    \"fr\": {\n      \"buildTarget\": \"your-app-name:build:development,fr\"\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>Now you can test the French version with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ng serve --configuration=fr<\/code><\/pre>\n\n\n\n<p>Now you&#8217;re ready to build separate versions of your app for each language. Just run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ng build --localize<\/code><\/pre>\n\n\n\n<p>This will generate:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/dist\/your-app-name\/en\/\n\/dist\/your-app-name\/fr\/<\/code><\/pre>\n\n\n\n<p>Each folder contains a fully translated version of your app, ready to be deployed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Adding a language switcher<\/h2>\n\n\n\n<p>Once you\u2019ve built localized versions of your Angular app (like <code>\/en\/<\/code>, <code>\/fr\/<\/code>), you probably want users to be able to switch between them.<\/p>\n\n\n\n<p>Since each language is essentially a separate version of the app living in its own folder, all you need is a basic link switcher.<\/p>\n\n\n\n<p>In your <code>app.component.ts<\/code>, define your list of supported locales:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export class AppComponent {<br>localesList = &#091;<br>{ code: 'en-US', label: 'English' },<br>{ code: 'fr', label: 'Fran\u00e7ais' }<br>];<br>}<\/code><\/pre>\n\n\n\n<p>And in your template, render the links:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;ul&gt;\n  &lt;li *ngFor=\"let locale of localesList\"&gt;\n    &lt;a href=\"\/{{ locale.code }}\/\"&gt;{{ locale.label }}&lt;\/a&gt;\n  &lt;\/li&gt;\n&lt;\/ul&gt;<\/code><\/pre>\n\n\n\n<p>Clicking these links will just navigate to a different localized version of your app, like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>\/en\/<\/code> \u2192 English version<\/li>\n\n\n\n<li><code>\/fr\/<\/code> \u2192 French version<\/li>\n<\/ul>\n\n\n\n<p>Each one lives inside its own folder, like <code>dist\/angular-i18n-demo\/browser\/en\/<\/code> and \u2026<code>\/fr\/<\/code>.<\/p>\n\n\n\n<p>You can test this out locally with <code>npx serve<\/code>. After running a localized build, just run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx serve dist\/angular-i18n-demo\/browser<\/code><\/pre>\n\n\n\n<p>Now visit:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>http:\/\/localhost:3000\/en\/<\/code><\/li>\n\n\n\n<li><code>http:\/\/localhost:3000\/fr\/<\/code><\/li>\n<\/ul>\n\n\n\n<p>You should see the correct translated versions, and your switcher links will work as expected.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXftXWj1spJfpl6NRjxx-CKHF87bTUNiBrKu-iGowB3-FugvJMCmdaK3nSv-P-7yYPAgUKQefxF9TPz96Wmemum-27wWWM6Hmsmmco7uSYE2IDVtYloAyJxDbNYjMwonQfwobgk-HQ?key=hzdCvloU5ZnzsO_oafvGRN1a\" alt=\"\"\/><\/figure>\n\n\n\n<p>If you deploy to something like Netlify or Firebase Hosting, the idea is the same \u2014 you just serve the folders for each locale. Clicking a language link loads that version of your app.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping up<\/h2>\n\n\n\n<p>If you\u2019ve followed everything up to this point, you now have a fully localized Angular app. You\u2019ve seen how to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Mark both template and code strings for translation<\/li>\n\n\n\n<li>Handle plurals, numbers, dates, and currencies properly<\/li>\n\n\n\n<li>Extract and manage translations using tools like POEditor<\/li>\n\n\n\n<li>Configure Angular to recognize multiple languages<\/li>\n\n\n\n<li>Build and serve separate versions of your app per language<\/li>\n<\/ul>\n\n\n\n<p>Angular\u2019s built-in localization system is powerful \u2014 especially for apps that don\u2019t need runtime language switching. But just keep in mind: it\u2019s built around compile-time localization. If your app needs to switch languages dynamically without a full page reload, you&#8217;ll want to consider libraries like <a href=\"https:\/\/github.com\/ngx-translate\/core\" rel=\"nofollow\">ngx-translate<\/a> or <a href=\"https:\/\/github.com\/jsverse\/transloco\" rel=\"nofollow\">Transloco<\/a>.<\/p>\n\n\n\n<p>Otherwise, Angular&#8217;s native i18n tooling gives you a clean, structured way to create fast, translated apps \u2014 with zero runtime overhead.<\/p>\n\n\n\n<p>That\u2019s it. You\u2019re now set up to build Angular apps that speak more than one language \u2014 and speak them well.<\/p>\n\n\n<div class=\"call-action my-4 d-flex justify-content-between align-items-md-center gap-4 flex-column flex-lg-row\"><div><h3 class=\"fs-4\">Ready to power up localization?<\/h3><span class=\"fs-6\">Subscribe to the POEditor platform today!<\/span><\/div><a class=\"btn btn-b-primary d-flex align-items-center justify-content-center px-4 py-3 flex-shrink-0\" \n\t\t\t\t\thref=\"https:\/\/poeditor.com\/pricing\/?utm_source=blog&#038;utm_medium=btn&#038;utm_campaign=cta_pricing\">See pricing<\/a><\/div>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Angular is a frontend JavaScript framework built for creating large, maintainable web applications. But out of the box, you\u2019re only able to display content in one language \u2014 whatever text you hardcode into your templates. If you&#8217;re building something for a global audience, or just want your app to support multiple languages, you&#8217;ll need to [&hellip;]<\/p>\n","protected":false},"author":9,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-6296","post","type-post","status-publish","format-standard","hentry","category-tutorials"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Angular internationalization and localization: A complete guide - POEditor Blog<\/title>\n<meta name=\"description\" content=\"Check out our comprehensive guide on Angular internationalization and localization to build Angular apps that speak more than one language.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Angular internationalization and localization: A complete guide - POEditor Blog\" \/>\n<meta property=\"og:description\" content=\"Check out our comprehensive guide on Angular internationalization and localization to build Angular apps that speak more than one language.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/\" \/>\n<meta property=\"og:site_name\" content=\"POEditor Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/POEditor\" \/>\n<meta property=\"article:published_time\" content=\"2025-04-28T06:07:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-04-20T12:51:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1603\" \/>\n\t<meta property=\"og:image:height\" content=\"1294\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Joel Olawanle\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@poeditor\" \/>\n<meta name=\"twitter:site\" content=\"@poeditor\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Joel Olawanle\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/\"},\"author\":{\"name\":\"Joel Olawanle\",\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/#\\\/schema\\\/person\\\/7c32041b74b3e09061cabde6e194862b\"},\"headline\":\"Angular internationalization and localization: A complete guide\",\"datePublished\":\"2025-04-28T06:07:00+00:00\",\"dateModified\":\"2026-04-20T12:51:17+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/\"},\"wordCount\":2374,\"publisher\":{\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/angular-internationalization-and-localization-1024x827.png\",\"articleSection\":[\"Tutorials\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/\",\"url\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/\",\"name\":\"Angular internationalization and localization: A complete guide - POEditor Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/angular-internationalization-and-localization-1024x827.png\",\"datePublished\":\"2025-04-28T06:07:00+00:00\",\"dateModified\":\"2026-04-20T12:51:17+00:00\",\"description\":\"Check out our comprehensive guide on Angular internationalization and localization to build Angular apps that speak more than one language.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/#primaryimage\",\"url\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/angular-internationalization-and-localization.png\",\"contentUrl\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/wp-content\\\/uploads\\\/2025\\\/04\\\/angular-internationalization-and-localization.png\",\"width\":1603,\"height\":1294,\"caption\":\"angular internationalization and localization\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/angular-internationalization-localization\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Angular internationalization and localization: A complete guide\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/\",\"name\":\"POEditor Blog\",\"description\":\"All about translation and localization management\",\"publisher\":{\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/#organization\",\"name\":\"POEditor\",\"url\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/11\\\/logo_head_512_transparent.png\",\"contentUrl\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/wp-content\\\/uploads\\\/2019\\\/11\\\/logo_head_512_transparent.png\",\"width\":512,\"height\":512,\"caption\":\"POEditor\"},\"image\":{\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/POEditor\",\"https:\\\/\\\/x.com\\\/poeditor\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/poeditor\\\/\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UCXAk1u8N49VRMAqNneENCFA\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/#\\\/schema\\\/person\\\/7c32041b74b3e09061cabde6e194862b\",\"name\":\"Joel Olawanle\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/30f391dce10587a611158f3f46b79cabfc72e00d891bf7ae84dd80cec0a6d71b?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/30f391dce10587a611158f3f46b79cabfc72e00d891bf7ae84dd80cec0a6d71b?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/30f391dce10587a611158f3f46b79cabfc72e00d891bf7ae84dd80cec0a6d71b?s=96&d=mm&r=g\",\"caption\":\"Joel Olawanle\"},\"url\":\"https:\\\/\\\/poeditor.com\\\/blog\\\/author\\\/joel-olawanle\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Angular internationalization and localization: A complete guide - POEditor Blog","description":"Check out our comprehensive guide on Angular internationalization and localization to build Angular apps that speak more than one language.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/","og_locale":"en_US","og_type":"article","og_title":"Angular internationalization and localization: A complete guide - POEditor Blog","og_description":"Check out our comprehensive guide on Angular internationalization and localization to build Angular apps that speak more than one language.","og_url":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/","og_site_name":"POEditor Blog","article_publisher":"https:\/\/www.facebook.com\/POEditor","article_published_time":"2025-04-28T06:07:00+00:00","article_modified_time":"2026-04-20T12:51:17+00:00","og_image":[{"width":1603,"height":1294,"url":"https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization.png","type":"image\/png"}],"author":"Joel Olawanle","twitter_card":"summary_large_image","twitter_creator":"@poeditor","twitter_site":"@poeditor","twitter_misc":{"Written by":"Joel Olawanle","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/#article","isPartOf":{"@id":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/"},"author":{"name":"Joel Olawanle","@id":"https:\/\/poeditor.com\/blog\/#\/schema\/person\/7c32041b74b3e09061cabde6e194862b"},"headline":"Angular internationalization and localization: A complete guide","datePublished":"2025-04-28T06:07:00+00:00","dateModified":"2026-04-20T12:51:17+00:00","mainEntityOfPage":{"@id":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/"},"wordCount":2374,"publisher":{"@id":"https:\/\/poeditor.com\/blog\/#organization"},"image":{"@id":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/#primaryimage"},"thumbnailUrl":"https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization-1024x827.png","articleSection":["Tutorials"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/","url":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/","name":"Angular internationalization and localization: A complete guide - POEditor Blog","isPartOf":{"@id":"https:\/\/poeditor.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/#primaryimage"},"image":{"@id":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/#primaryimage"},"thumbnailUrl":"https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization-1024x827.png","datePublished":"2025-04-28T06:07:00+00:00","dateModified":"2026-04-20T12:51:17+00:00","description":"Check out our comprehensive guide on Angular internationalization and localization to build Angular apps that speak more than one language.","breadcrumb":{"@id":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/#primaryimage","url":"https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization.png","contentUrl":"https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2025\/04\/angular-internationalization-and-localization.png","width":1603,"height":1294,"caption":"angular internationalization and localization"},{"@type":"BreadcrumbList","@id":"https:\/\/poeditor.com\/blog\/angular-internationalization-localization\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/poeditor.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Angular internationalization and localization: A complete guide"}]},{"@type":"WebSite","@id":"https:\/\/poeditor.com\/blog\/#website","url":"https:\/\/poeditor.com\/blog\/","name":"POEditor Blog","description":"All about translation and localization management","publisher":{"@id":"https:\/\/poeditor.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/poeditor.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/poeditor.com\/blog\/#organization","name":"POEditor","url":"https:\/\/poeditor.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/poeditor.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2019\/11\/logo_head_512_transparent.png","contentUrl":"https:\/\/poeditor.com\/blog\/wp-content\/uploads\/2019\/11\/logo_head_512_transparent.png","width":512,"height":512,"caption":"POEditor"},"image":{"@id":"https:\/\/poeditor.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/POEditor","https:\/\/x.com\/poeditor","https:\/\/www.linkedin.com\/company\/poeditor\/","https:\/\/www.youtube.com\/channel\/UCXAk1u8N49VRMAqNneENCFA"]},{"@type":"Person","@id":"https:\/\/poeditor.com\/blog\/#\/schema\/person\/7c32041b74b3e09061cabde6e194862b","name":"Joel Olawanle","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/30f391dce10587a611158f3f46b79cabfc72e00d891bf7ae84dd80cec0a6d71b?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/30f391dce10587a611158f3f46b79cabfc72e00d891bf7ae84dd80cec0a6d71b?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/30f391dce10587a611158f3f46b79cabfc72e00d891bf7ae84dd80cec0a6d71b?s=96&d=mm&r=g","caption":"Joel Olawanle"},"url":"https:\/\/poeditor.com\/blog\/author\/joel-olawanle\/"}]}},"_links":{"self":[{"href":"https:\/\/poeditor.com\/blog\/wp-json\/wp\/v2\/posts\/6296","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/poeditor.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/poeditor.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/poeditor.com\/blog\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/poeditor.com\/blog\/wp-json\/wp\/v2\/comments?post=6296"}],"version-history":[{"count":15,"href":"https:\/\/poeditor.com\/blog\/wp-json\/wp\/v2\/posts\/6296\/revisions"}],"predecessor-version":[{"id":6315,"href":"https:\/\/poeditor.com\/blog\/wp-json\/wp\/v2\/posts\/6296\/revisions\/6315"}],"wp:attachment":[{"href":"https:\/\/poeditor.com\/blog\/wp-json\/wp\/v2\/media?parent=6296"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/poeditor.com\/blog\/wp-json\/wp\/v2\/categories?post=6296"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/poeditor.com\/blog\/wp-json\/wp\/v2\/tags?post=6296"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}