{"id":53254,"date":"2023-05-17T14:42:12","date_gmt":"2023-05-17T12:42:12","guid":{"rendered":"https:\/\/phrase.com\/?p=53254"},"modified":"2023-10-25T10:46:46","modified_gmt":"2023-10-25T08:46:46","slug":"nextjs-i18n","status":"publish","type":"post","link":"https:\/\/phrase.com\/blog\/posts\/nextjs-i18n\/","title":{"rendered":"A Step-by-Step Guide to Next.js Internationalization"},"content":{"rendered":"\n<div id=\"acf\/text-block_e92580faa2e14b16f0af10388b5bcc27\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Next.js is one of the most popular frameworks for React. To help you implement multilingual support for your app, this tutorial will guide you through all of the Next.js internationalization (i18n) essentials.<\/p>\n<p>We will localize our UI component content using the <code>next-i18next<\/code> library and localize routes using Next\u2019s native i18n features. Finally, we will make sure to cover i18n for both SSR (server-side rendering) and SSG (static site generation). Let&#8217;s begin!<\/p>\n<p>\ud83d\udd17 <em>Resource \u00bb<\/em> For localizing a Next.js app using the App Router and next-intl. library, please feel free to take a look at our tutorial on <a href=\"https:\/\/phrase.com\/blog\/posts\/next-js-app-router-localization-next-intl\/\">Next.js App Router localization with next-intl<\/a>.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n\n<div id=\"acf\/blog-cta-block_f7bc380e6c8197e297fa1c10a3e250e7\" class=\"pxblock pxblock--blog-cta bg--green image--orientation-landscape\">\n\t<div class=\"block-container\">\n\t\t\t\t\t<div class=\"image image--align-middle\">\n\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1260\" height=\"992\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero.png\" class=\"attachment-original size-original\" alt=\"String Management UI visual | Phrase\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero.png 1260w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-300x236.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-1024x806.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-768x605.png 768w\" sizes=\"(max-width: 1260px) 100vw, 1260px\" \/>\t\t\t<\/div>\n\t\t\t\t<div class=\"content\">\n\t\t\t<p class=\"subhead\">Phrase Strings<\/p>\n<p class=\"secondary h6\">Take your web or mobile app global without any hassle<\/p>\n<div class=\"text--copy\">\n<p class=\"small\">Adapt your software, website, or video game for global audiences with the leanest and most realiable software localization platform.<\/p>\n<p><a class=\"btn btn--outline\" href=\"https:\/\/phrase.com\/platform\/strings\/\">Explore Phrase Strings<\/a><\/p>\n<\/div>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n\n<div id=\"acf\/text-block_dfc580553c9992c8d936e2b485269c1a\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_69_1 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Overview<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/phrase.com\/blog\/posts\/nextjs-i18n\/#native-nextjs-i18n\" title=\"Native Next.js i18n\">Native Next.js i18n<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/phrase.com\/blog\/posts\/nextjs-i18n\/#libraries-we-will-be-using\" title=\"Libraries we will be using\">Libraries we will be using<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/phrase.com\/blog\/posts\/nextjs-i18n\/#our-app-demo-i18n-news-reader\" title=\"Our app demo: i18n News Reader\">Our app demo: i18n News Reader<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/phrase.com\/blog\/posts\/nextjs-i18n\/#initial-setup\" title=\"Initial setup\">Initial setup<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/phrase.com\/blog\/posts\/nextjs-i18n\/#displaying-localized-news-from-a-backend\" title=\"Displaying localized news from a backend\">Displaying localized news from a backend<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/phrase.com\/blog\/posts\/nextjs-i18n\/#using-next-i18next-to-localize-component-strings\" title=\"Using next-i18next to localize component strings\">Using next-i18next to localize component strings<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/phrase.com\/blog\/posts\/nextjs-i18n\/#working-with-localized-routes\" title=\"Working with localized routes\">Working with localized routes<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/phrase.com\/blog\/posts\/nextjs-i18n\/#statically-generating-localized-pages\" title=\"Statically generating localized pages\">Statically generating localized pages<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/phrase.com\/blog\/posts\/nextjs-i18n\/#making-our-language-switcher-functional\" title=\"Making our language switcher functional\">Making our language switcher functional<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/phrase.com\/blog\/posts\/nextjs-i18n\/#ready-to-start-translating\" title=\"Ready to start translating\">Ready to start translating<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"native-nextjs-i18n\"><\/span>Native Next.js i18n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Since v10, Next.js has had built-in support for internationalized routing. With this addition, given some locale configuration, Next.js automatically handles localized routing.<\/p>\n<p>Included out of the box in Next.js are sub-path and domain routing. Sub-path routing is where the locale is part of the URL, like <code>\/blog<\/code>, <code>\/fr\/blog<\/code>, <code>\/es\/blog<\/code>. Domain routing has the locale appear in the top-level domain, like <code>mywebsite.com\/blog<\/code>, <code>mywebsite.fr\/blog<\/code>, <code>mywebsite.nl\/blog<\/code>.<\/p>\n<p>Of course, we will need to configure the i18n in our app for these routes to work. Let\u2019s see this in practice by building a small demo app.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"libraries-we-will-be-using\"><\/span>Libraries we will be using<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>We will be using the following NPM packages (with the version number in parentheses):<\/p>\n<ul>\n<li><a href=\"https:\/\/nextjs.org\/\">Next.js<\/a>\u00a0(13.0.0)<\/li>\n<li><a href=\"https:\/\/www.i18next.com\/\">i18next<\/a>\u00a0(22.0.4)<\/li>\n<li><a href=\"https:\/\/react.i18next.com\/\">react-i18next<\/a>\u00a0(12.0.0)<\/li>\n<li><a href=\"https:\/\/github.com\/i18next\/next-i18next\">next-i18next<\/a>\u00a0(12.0.1)<\/li>\n<li><a href=\"https:\/\/tailwindcss.com\/\">Tailwind CSS<\/a> (3.1.8)\u2014optional<\/li>\n<\/ul>\n<h2><span class=\"ez-toc-section\" id=\"our-app-demo-i18n-news-reader\"><\/span>Our app demo: i18n News Reader<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>We will be building a news reader app in Next.js. Here&#8217;s what its homepage will look like when we\u2019re done:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-53255 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-1024x666.jpg\" alt=\"i18n News Reader Homepage | Phrase\" width=\"1024\" height=\"666\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-1024x666.jpg 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-300x195.jpg 300w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-768x499.jpg 768w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-1536x998.jpg 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-2048x1331.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>The homepage will list news articles in a card format, presenting them in the default browser locale.<\/p>\n<p>\ud83d\uddd2\ufe0f <em>Note \u00bb<\/em> <a href=\"https:\/\/nextjs.org\/docs\/advanced-features\/i18n-routing#automatic-locale-detection\">Next.js automatically detects<\/a> the default locale preferred by the user based on the <code>Accept-Language<\/code> header.<\/p>\n<p>If we want to read the same webpage in a different language, say Spanish, we will be able to choose it from a language selector drop-down beside the app title. Here\u2019s what the home page will look like when Spanish ( <code>es<\/code>) is selected:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-53261 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-in-Spanish-1024x666.jpg\" alt=\"i18n News Reader Homepage in Spanish | Phrase\" width=\"1024\" height=\"666\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-in-Spanish-1024x666.jpg 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-in-Spanish-300x195.jpg 300w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-in-Spanish-768x499.jpg 768w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-in-Spanish-1536x998.jpg 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/i18n-News-Reader-Homepage-in-Spanish-2048x1331.jpg 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>To read a news article in detail, we will click on its <em>Read more<\/em> button. Next.js will route to the article in the currently selected locale, and we will see the news detail page in our preferred language. That\u2019s our app in a nutshell. Let&#8217;s build it!<\/p>\n<h2><span class=\"ez-toc-section\" id=\"initial-setup\"><\/span>Initial setup<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Let&#8217;s start from scratch and spin up a new Next.js app with the following command-line command:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">$ npx create-next-app@latest<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_aae4546ebd56c70646665ebe433956fc\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Follow the prompts and give your project a suitable name.<\/p>\n<p>Let&#8217;s build our homepage, starting with adding a <code>Header<\/code> component, which has the app title along with a <code>LanguageSwitcher<\/code> component (we will make that one next):<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ components\/Header.jsx<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> Link <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next\/link'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> LanguageSwitcher <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/LanguageSwitcher'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Header<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> (\n    {<span class=\"hljs-comment\">\/* CSS classes removed for brevity. *\/<\/span>}\n    &lt;header&gt;\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">'\/'<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n            i18n News Reader\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">LanguageSwitcher<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n    &lt;<span class=\"hljs-regexp\">\/header&gt;\n  );\n}<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_bf9666012d7cff315e05d22c1ddd6094\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p><span role=\"img\" aria-label=\"\ud83d\udd17\">\ud83d\udd17<\/span> <span class=\"notion-enable-hover\" data-token-index=\"1\">Resource \u00bb <\/span>You can get the complete code of our demo app, including CSS styles, from <a class=\"discussion-id-00f22c1b-daf2-42fd-800f-50360a424f77 notion-link-token notion-focusable-token notion-enable-hover\" tabindex=\"0\" href=\"https:\/\/github.com\/PhraseApp-Blog\/next-i18next-demo-2023\" rel=\"noopener noreferrer\" data-token-index=\"3\"><span class=\"link-annotation-unknown-block-id--280684573\">our GitHub repo<\/span><\/a>.<\/p>\n<p>For the <code>LanguageSwitcher<\/code> component, we have a <code>select<\/code> element with two <code>option<\/code> values:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ components\/LanguageSwitcher.jsx<\/span>\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">LanguageSwitcher<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">select<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">'en'<\/span>&gt;<\/span>English<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">'es'<\/span>&gt;<\/span>Espa\u00f1ol<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">select<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_098cde5f6bdebed1aedb118498d09b02\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Let&#8217;s include our <code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"1\">Header<\/span><\/code> in the\u00a0<code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"3\">app.js<\/span><\/code> file:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ pages\/app.js<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> Header <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/components\/Header'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'..\/styles\/globals.css'<\/span>;\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">MyApp<\/span>(<span class=\"hljs-params\">{ Component, pageProps }<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Header<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Component<\/span> {<span class=\"hljs-attr\">...pageProps<\/span>} \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span>\n  );\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> MyApp;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_f233713dcd7fc4ed2b7b131d4b3020c8\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<h2><span class=\"ez-toc-section\" id=\"displaying-localized-news-from-a-backend\"><\/span>Displaying localized news from a backend<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Now we need to work on news items. The news data will be served from a separate\u00a0<a href=\"https:\/\/expressjs.com\/\">Express.js<\/a> app that simulates a production backend API. The mock backend code is a bit outside the scope of this article; all we need to know for our purposes is how to fetch data from it. Two endpoints, <code>http:\/\/localhost:3000\/en<\/code> and <code>http:\/\/localhost:3000\/es<\/code>, serve news data from English and Spanish JSON files, respectively.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-comment\">\/\/ data\/en.json<\/span>\n\n&#91;\n  {\n    <span class=\"hljs-attr\">\"id\"<\/span>: <span class=\"hljs-number\">1<\/span>,\n    <span class=\"hljs-attr\">\"slug\"<\/span>: <span class=\"hljs-string\">\"energy-storage-system-market-demand-is-projected-to-reach-44071-gw-in-2028\"<\/span>,\n    <span class=\"hljs-attr\">\"title\"<\/span>: <span class=\"hljs-string\">\"Energy Storage System Market demand is Projected to Reach 440.71 GW in 2028\"<\/span>,\n    <span class=\"hljs-attr\">\"description\"<\/span>: <span class=\"hljs-string\">\"...\"<\/span>,\n    <span class=\"hljs-attr\">\"content\"<\/span>: <span class=\"hljs-string\">\"...\"<\/span>,\n    <span class=\"hljs-attr\">\"date\"<\/span>: <span class=\"hljs-string\">\"August 16, 2022\"<\/span>\n  },\n \n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n]<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-comment\">\/\/ data\/es.json<\/span>\n\n&#91;\n  {\n    <span class=\"hljs-attr\">\"id\"<\/span>: <span class=\"hljs-number\">1<\/span>,\n    <span class=\"hljs-attr\">\"slug\"<\/span>: <span class=\"hljs-string\">\"energy-storage-system-market-demand-is-projected-to-reach-44071-gw-in-2028\"<\/span>,\n    <span class=\"hljs-attr\">\"title\"<\/span>: <span class=\"hljs-string\">\"Se prev\u00e9 que la demanda del mercado de sistemas de almacenamiento de energ\u00eda alcance los 440,71 GW en 2028\"<\/span>,\n    <span class=\"hljs-attr\">\"description\"<\/span>: <span class=\"hljs-string\">\"...\"<\/span>,\n    <span class=\"hljs-attr\">\"content\"<\/span>: <span class=\"hljs-string\">\"...\"<\/span>,\n    <span class=\"hljs-attr\">\"date\"<\/span>: <span class=\"hljs-string\">\"16 de agosto de 2022\"<\/span>\n  },\n  \n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n]<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_7d124baf35109dea3e80b813469df295\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>\ud83d\udd17 <em>Resource \u00bb<\/em> If you\u2019re curious, you can get the Express backend code from <a href=\"https:\/\/github.com\/PhraseApp-Blog\/next-i18next-demo-backend-2023\">our GitHub repo<\/a>.<\/p>\n<p>Let\u2019s fetch this news data. For this, we will export Next\u2019s <a href=\"https:\/\/nextjs.org\/docs\/basic-features\/data-fetching\/get-server-side-props\"><code>getServerSideProps<\/code><\/a> for server-side rendering (SSR), which pre-renders our\u00a0<code>index.js<\/code>\u00a0page on each request:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ pages\/index.js<\/span>\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> getServerSideProps = <span class=\"hljs-keyword\">async<\/span> (context) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> { locale } = context;\n  <span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">`http:\/\/localhost:3001\/<span class=\"hljs-subst\">${locale}<\/span>`<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> res.json();\n\n  <span class=\"hljs-keyword\">return<\/span> {\n    <span class=\"hljs-attr\">props<\/span>: {\n      data,\n    },\n  };\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_d16197c5f47795be9c12f3033cc55841\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Note that we are using the <a href=\"https:\/\/nextjs.org\/docs\/api-reference\/data-fetching\/get-server-side-props#context-parameter\"><code>context<\/code><\/a> parameter, made available to us in <code>getServerSideProps<\/code>, to get the active locale. This <code>locale<\/code>\u2019s value will be what Next.js automatically detects from the browser\u2019s <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTTP\/Headers\/Accept-Language\">Accept-Language<\/a> header (with a fallback, see following note). In our case it will be either <code>en<\/code> (English) or <code>es<\/code> (Spanish).<\/p>\n<p>\ud83d\uddd2\ufe0f <em>Note \u00bb<\/em> If the automatically detected <code>Accept-Language<\/code> locale is not supported by our app, Next will use our configured default locale instead. We cover this configuration in the next section.<\/p>\n<p>In the same <code>pages\/index.js<\/code> file, we will use the <code>data<\/code> property returned from <code>getServerSideProps<\/code> to render our news items in the <code>Home<\/code> component.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ pages\/index.js<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> Head <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next\/head'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ `data` is returned from getServerSideProps and is <\/span>\n<span class=\"hljs-comment\">\/\/ available as a component prop here.<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span>(<span class=\"hljs-params\">{ data }<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Head<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">title<\/span>&gt;<\/span>i18n News Reader<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">title<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Head<\/span>&gt;<\/span>\n\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        {data.map((news, index) =&gt; (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{index}<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{news.date}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n            \n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span>&gt;<\/span>{news.title}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n            \n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{news.description}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        ))}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> getServerSideProps = <span class=\"hljs-keyword\">async<\/span> (context) =&gt; {\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_d1413be062c607f67548ee3da1f3eed7\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<h2><span class=\"ez-toc-section\" id=\"using-next-i18next-to-localize-component-strings\"><\/span><strong>Using next-i18next to localize component strings<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Let&#8217;s start localizing our UI components using the <a href=\"https:\/\/github.com\/i18next\/next-i18next#readme\">next-i18next<\/a> library. next-i18next provides a way to manage translated <em>content<\/em> and is built on top oBy default, next-i18next expects the translations to be at \/public\/locales\/[localeName]\/common.json. So let\u2019s add our English translations to public\/locales\/en\/common.json.f the very popular i18next library.<\/p>\n<p>First, let&#8217;s install next-i18next and its peer dependencies by running the following from the command-line:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">$ npm i next-i18next react-i18next i18next<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_426e8ace7bac332319650b17b1f3b457\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>By default, next-i18next expects the translations to be at <code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"1\">\/public\/locales\/[localeName]\/common.json<\/span><\/code>. So let\u2019s add our English translations to <code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"3\">public\/locales\/en\/common.json<\/span><\/code>.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-comment\">\/\/ public\/locales\/en\/common.json <\/span>\n\n{\n  <span class=\"hljs-attr\">\"app_title\"<\/span>: <span class=\"hljs-string\">\"i18n News Reader\"<\/span>,\n  <span class=\"hljs-attr\">\"active_locale\"<\/span>: <span class=\"hljs-string\">\"English\"<\/span>,\n  <span class=\"hljs-attr\">\"button_label\"<\/span>: <span class=\"hljs-string\">\"Read More\"<\/span>,\n  <span class=\"hljs-attr\">\"homepage_nav_link_label\"<\/span>: <span class=\"hljs-string\">\"Go Back\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_e14ff63999f44fa1f8bff38bd2bf7068\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Our Spanish translations will, of course, go in their respective JSON file.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-comment\">\/\/ public\/locales\/es\/common.json <\/span>\n\n{\n  <span class=\"hljs-attr\">\"app_title\"<\/span>: <span class=\"hljs-string\">\"Lector de noticias i18n\"<\/span>,\n  <span class=\"hljs-attr\">\"active_locale\"<\/span>: <span class=\"hljs-string\">\"Espa\u00f1ol\"<\/span>,\n  <span class=\"hljs-attr\">\"button_label\"<\/span>: <span class=\"hljs-string\">\"Lee mas\"<\/span>,\n  <span class=\"hljs-attr\">\"homepage_nav_link_label\"<\/span>: <span class=\"hljs-string\">\"Regresa\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_41d72153901f16b32df4697f7c59a6d4\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>It\u2019s time to set up our i18n configuration files, starting with\u00a0<code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"1\">next-i18next.config.js<\/span><\/code> at the root of our project.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ next-i18next.config.js<\/span>\n\n<span class=\"hljs-built_in\">module<\/span>.exports = {\n  <span class=\"hljs-attr\">debug<\/span>: process.env.NODE_ENV === <span class=\"hljs-string\">'development'<\/span>,\n  <span class=\"hljs-attr\">i18n<\/span>: {\n    <span class=\"hljs-attr\">locales<\/span>: &#91;<span class=\"hljs-string\">'en'<\/span>, <span class=\"hljs-string\">'es'<\/span>],\n    <span class=\"hljs-attr\">defaultLocale<\/span>: <span class=\"hljs-string\">'en'<\/span>,\n  },\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_594d90175f6693e1b0312c9629a1a484\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>\ud83d\udd17 <em>Resource \u00bb<\/em> We can customize the file paths to our translation files. Find out how in <a href=\"https:\/\/github.com\/i18next\/next-i18next#2-translation-content\">the official documentation<\/a>.<\/p>\n<p>\ud83d\uddd2\ufe0f <em>Note \u00bb<\/em> As we mentioned earlier, Next will fall back to the <code>defaultLocale<\/code> if the automatically detected locale is not in our supported locale list. We can <a href=\"https:\/\/nextjs.org\/docs\/advanced-features\/i18n-routing#disabling-automatic-locale-detection\">disable automatic locale detection<\/a>. We can also override it using <a href=\"https:\/\/nextjs.org\/docs\/advanced-features\/i18n-routing#leveraging-the-next_locale-cookie\">a special cookie<\/a>.<\/p>\n<p>This syntax will be familiar to you if you&#8217;ve worked with <a href=\"https:\/\/react.i18next.com\/\">react-i18next<\/a>. We\u2019re simply defining what our supported and default locales are.<\/p>\n<p>To keep our config consistent between next-i18next and Next\u2019s own <a href=\"https:\/\/nextjs.org\/docs\/advanced-features\/i18n-routing\">internationalized routing<\/a>, we can pass our <code>i18n<\/code> config to Next\u2019s\u00a0<code>next.config.js<\/code>\u00a0file:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ next.config.js<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> { i18n } = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'.\/next-i18next.config.js'<\/span>);\n\n<span class=\"hljs-built_in\">module<\/span>.exports = {\n <span class=\"hljs-comment\">\/\/...<\/span>\n i18n, \n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_ce5ae81e0c76fb5305b300ae592161e1\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Now let&#8217;s wrap our <code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"1\">MyApp<\/span><\/code> with the <code><span class=\"discussion-id-d27c9edf-7cd9-485f-abe3-f9eb0a0ea1c5 notion-enable-hover\" spellcheck=\"false\" data-token-index=\"3\">appWithTranslation<\/span><\/code>\u00a0Higher-Order Component (HOC), which is responsible for adding an <a class=\"discussion-id-e890e9e7-489d-4142-a5da-17f9d0c294b6 notion-link-token notion-focusable-token notion-enable-hover\" tabindex=\"0\" href=\"https:\/\/react.i18next.com\/latest\/i18nextprovider\" rel=\"noopener noreferrer\" data-token-index=\"5\"><span class=\"link-annotation-unknown-block-id-1755997219\">I18nextProvider<\/span><\/a> to our app.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ pages\/_app.js<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> { appWithTranslation } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-i18next'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Header <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/components\/Header'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'..\/styles\/globals.css'<\/span>;\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">MyApp<\/span>(<span class=\"hljs-params\">{ Component, pageProps }<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Header<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Component<\/span> {<span class=\"hljs-attr\">...pageProps<\/span>} \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span>\n  );\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> appWithTranslation(MyApp);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_aa94c7304924f5f659cfc9f5d873b7ae\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>When we call <code>appWithTranslation<\/code>, next-i18next will wrap our app with an <code>I18nextProvider<\/code>. This ensures that an instance of an i18next object, aware of our active locale and its translations, is available to all our components. We can then call a handy <code>useTranslation<\/code> hook to fetch our translations.<\/p>\n<p>Let\u2019s do just that by translating our <code>Header<\/code> component. To render translations in JSX, we can destructure a <code>t()<\/code> function from <code>useTranslation<\/code>.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ components\/Header.jsx<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> { useTranslation } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-i18next'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Link <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next\/link'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Header<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> { t } = useTranslation();\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">header<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">'\/'<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n            {\/* We simply give t() our translation key, and\n                it renders its value in the active locale. *\/}\n            {t('app_title')}\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">LanguageSwitcher<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">header<\/span>&gt;<\/span><\/span>\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_24a197c03d7f52a12e40339814de46bf\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Next, let\u2019s translate the homepage. Our <code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"1\">Home<\/span><\/code> component is rendered on the server. So, to translate it, we will need to use the <code><span class=\"discussion-id-a0d47eca-c482-449b-ad1a-55e409a6cc24 notion-enable-hover\" spellcheck=\"false\" data-token-index=\"3\">serverSideTranslation<\/span><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"4\">s<\/span><\/code> function provided by <code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"6\">next-i18next<\/span><\/code>. During SSR, this function helps pass translations and config as props to our page components. Here&#8217;s how to use it with <code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"8\">getServerSideProps<\/span><\/code>:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ pages\/index.js<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> { useTranslation } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-i18next'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { serverSideTranslations } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-i18next\/serverSideTranslations'<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> Head <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next\/head'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Link <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next\/link'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span>(<span class=\"hljs-params\">{ data }<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> { t } = useTranslation();\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Head<\/span>&gt;<\/span>\n\t\t\t\t{\/* Just as before, we use t('message_key') to \n            translate. *\/}\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">title<\/span>&gt;<\/span>{t('app_title')}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">title<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Head<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        {\/* ... *\/}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> getServerSideProps = <span class=\"hljs-keyword\">async<\/span> (context) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> { locale } = context;\n  <span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">`http:\/\/localhost:3001\/<span class=\"hljs-subst\">${locale}<\/span>`<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> res.json();\n\n  <span class=\"hljs-keyword\">return<\/span> {\n    <span class=\"hljs-attr\">props<\/span>: {\n\n      <span class=\"hljs-comment\">\/\/ Spread the returned object into our `props` to expose<\/span>\n      <span class=\"hljs-comment\">\/\/ them to our component during SSR.<\/span>\n      ...(<span class=\"hljs-keyword\">await<\/span> serverSideTranslations(locale, &#91;<span class=\"hljs-string\">'common'<\/span>])),\n\n      data,\n    },\n  };\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_d76b0e62f3dca70b35f7f067c8b40e07\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>We are passing the extracted <code>locale<\/code> from the <code>context<\/code> along with the translation namespace in the array. Note that we are adding the <code>common<\/code> namespace explicitly here. We can pull one or more namespaces as long as they match our namespace file paths (e.g. <code>common.json<\/code>). <code>common<\/code> is the default namespace, hence it is optional to use it here.<\/p>\n<p>\ud83e\udd3f <em>Go deeper \u00bb<\/em> Read more about <a href=\"https:\/\/www.i18next.com\/principles\/namespaces\">namespaces<\/a> in the i18next documentation<em>.<\/em><\/p>\n<p>Until now, we\u2019ve only worked with the homepage. Let\u2019s generate localized dynamic pages for our news articles and get the language selection drop-down working.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"working-with-localized-routes\"><\/span>Working with localized routes<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>In order to create localized routes, first we need to make the <code>locale<\/code> in <code>getServerSideProps<\/code> available to our <code>Home<\/code> component:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ pages\/index.js<\/span>\n\n<span class=\"hljs-comment\">\/\/ `locale` is returned from `getServerSideProps` <\/span>\n<span class=\"hljs-comment\">\/\/ below, and is available as a component prop here.<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span>(<span class=\"hljs-params\">{ data, locale }<\/span>) <\/span>{\n\n  <span class=\"hljs-comment\">\/\/ We will look at using `locale` here in a moment<\/span>\n\n}\n\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> getServerSideProps = <span class=\"hljs-keyword\">async<\/span> (context) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> { locale } = context;\n  <span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">`http:\/\/localhost:3001\/<span class=\"hljs-subst\">${locale}<\/span>`<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> res.json();\n\n  <span class=\"hljs-keyword\">return<\/span> {\n    <span class=\"hljs-attr\">props<\/span>: {\n      data,\n      \n      <span class=\"hljs-comment\">\/\/ We expose the `locale` to the `Home` <\/span>\n      <span class=\"hljs-comment\">\/\/ component above.<\/span>\n\t\t\tlocale \n    },\n  };\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_e8c45eb87d0607e35ef79937b83727ce\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Now we can use the <a class=\"discussion-id-69b146ba-2c32-4802-beae-a15911eb5934 notion-link-token notion-focusable-token notion-enable-hover\" tabindex=\"0\" href=\"https:\/\/nextjs.org\/docs\/api-reference\/next\/link\" rel=\"noopener noreferrer\" data-token-index=\"2\"><span class=\"link-annotation-unknown-block-id--135666279\">&lt;Link&gt;<\/span><\/a> component provided by Next.js to create dynamic, localized links. We do this by passing the <code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"4\">locale<\/span><\/code> prop to our <code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"6\">&lt;Link&gt;<\/span><\/code>s.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ pages\/index.js<\/span>\n\n<span class=\"hljs-comment\">\/\/...<\/span>\n<span class=\"hljs-keyword\">import<\/span> Link <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next\/link'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Home<\/span>(<span class=\"hljs-params\">{ data, locale }<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> { t } = useTranslation();\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Head<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">title<\/span>&gt;<\/span>{t('app_title')}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">title<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Head<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        {data.map((news, id) =&gt; (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{id}<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{news.date}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\n            {\/* The article title now navigates to\n                the article details page... *\/}\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span>\n              <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">{{<\/span>\n                <span class=\"hljs-attr\">pathname:<\/span> '\/<span class=\"hljs-attr\">news<\/span>\/&#91;<span class=\"hljs-attr\">slug<\/span>]',\n                <span class=\"hljs-attr\">query:<\/span> { <span class=\"hljs-attr\">slug:<\/span> <span class=\"hljs-attr\">news.slug<\/span> },\n              }}\n              <span class=\"hljs-attr\">locale<\/span>=<span class=\"hljs-string\">{locale}<\/span>\n            &gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span>&gt;<\/span>{news.title}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{news.description}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\n            {\/* ...the \"Read more\" button also goes to the\n                article details page. *\/}\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span>\n              <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">{{<\/span>\n                <span class=\"hljs-attr\">pathname:<\/span> '\/<span class=\"hljs-attr\">news<\/span>\/&#91;<span class=\"hljs-attr\">slug<\/span>]',\n                <span class=\"hljs-attr\">query:<\/span> { <span class=\"hljs-attr\">slug:<\/span> <span class=\"hljs-attr\">news.slug<\/span> },\n              }}\n              <span class=\"hljs-attr\">locale<\/span>=<span class=\"hljs-string\">{locale}<\/span>&gt;<\/span>\n              {t('button_label')}\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        ))}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> getServerSideProps = <span class=\"hljs-keyword\">async<\/span> (context) =&gt; {\n  <span class=\"hljs-comment\">\/\/...<\/span>\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_cd8853f119349d4a2d17fa5f691c15dc\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Look at the <code>href<\/code> prop of the <a href=\"https:\/\/nextjs.org\/docs\/api-reference\/next\/link\"><code>&lt;Link&gt;<\/code><\/a> component. We pass a\u00a0<a href=\"https:\/\/nextjs.org\/docs\/api-reference\/next\/link#with-url-object\">URL object<\/a>\u00a0to it with the <code>pathname<\/code> and <code>query<\/code> properties. Let&#8217;s see what both of these are:<\/p>\n<ul>\n<li><code>pathname<\/code> is the page&#8217;s path in the <code>pages<\/code> directory. In our case, we want to navigate to the dynamic <code>\/pages\/news\/[slug].js<\/code> page, so our path is <code>\/news\/[slug]<\/code>.<\/li>\n<li><code>query<\/code> is an object with the dynamic segment, <code>slug<\/code> in this case. Each of our <code>news<\/code> items has a unique slug that we pass in the <code>query<\/code> object.<\/li>\n<\/ul>\n<p>When our <code>&lt;Link&gt;<\/code> renders, we get an <code>&lt;a&gt;<\/code> tag that looks like the following.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"\/news\/energy-storage-system-market-demand-is-projected-to-reach-44071-gw-in-2028\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_b1924e9532578e52f29455720b8afb94\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>By default, if we pass our default locale to <code>&lt;Link&gt;<\/code> as the <code>locale<\/code> prop, we will get a URL without a locale component. So, in our case, if we pass <code>en<\/code> as the <code>locale<\/code>, we will get a URL like the one above.<\/p>\n<p>However, when we change the translation language to Spanish (<code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"1\">es<\/span><\/code>) via the <code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"3\">LanguageSwitcher<\/span><\/code> component, our <code><span class=\"notion-enable-hover\" spellcheck=\"false\" data-token-index=\"5\">&lt;Link&gt;<\/span><\/code>s will add the locale as the first part of the URL:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"\/es\/news\/energy-storage-system-market-demand-is-projected-to-reach-44071-gw-in-2028\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_4a89766ef1087e1331605e1e7adb2d27\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<h2><span class=\"ez-toc-section\" id=\"statically-generating-localized-pages\"><\/span>Statically generating localized pages<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Next\u2019s built-in SSG (Static Site Generation) allows us to pre-render pages that don\u2019t have dynamic content or that change infrequently, speeding up initial page loads. Localizing our statically-generated pages isn\u2019t too difficult because Next.js provides our configured locales to its <a href=\"https:\/\/nextjs.org\/docs\/basic-features\/data-fetching\/get-static-paths\">getStaticPaths<\/a> SSG function. Let\u2019s use this to create localized news details pages in our demo.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ pages\/news\/&#91;slug].js<\/span>\n\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n\n<span class=\"hljs-comment\">\/\/ We destructure our `locales` array from the <\/span>\n<span class=\"hljs-comment\">\/\/ context parameter object.<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> getStaticPaths = <span class=\"hljs-keyword\">async<\/span> ({ locales }) =&gt; {\n\n  <span class=\"hljs-comment\">\/\/ Grab the news data from our mock backend for<\/span>\n  <span class=\"hljs-comment\">\/\/ our default locale.<\/span>\n  <span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">'http:\/\/localhost:3001\/'<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> res.json();\n\n  <span class=\"hljs-comment\">\/\/ Create an array of path objects, one for each <\/span>\n  <span class=\"hljs-comment\">\/\/ locale + news item. For example, if we had <\/span>\n  <span class=\"hljs-comment\">\/\/ two news item with slugs 'foo' and 'bar', our <\/span>\n  <span class=\"hljs-comment\">\/\/ `paths` array would contain four entries:<\/span>\n  <span class=\"hljs-comment\">\/\/   - { params: { slug: 'foo' }, locale: 'en' }<\/span>\n  <span class=\"hljs-comment\">\/\/   - { params: { slug: 'foo' }, locale: 'es' }<\/span>\n  <span class=\"hljs-comment\">\/\/   - { params: { slug: 'bar' }, locale: 'en' }<\/span>\n  <span class=\"hljs-comment\">\/\/   - { params: { slug: 'bar' }, locale: 'es' }<\/span>\n  <span class=\"hljs-keyword\">const<\/span> paths = data.flatMap(<span class=\"hljs-function\">(<span class=\"hljs-params\">news<\/span>) =&gt;<\/span> {\n    <span class=\"hljs-keyword\">return<\/span> locales.map(<span class=\"hljs-function\">(<span class=\"hljs-params\">locale<\/span>) =&gt;<\/span> ({\n      <span class=\"hljs-attr\">params<\/span>: {\n        <span class=\"hljs-attr\">slug<\/span>: news.slug,\n      },\n      locale,\n    }));\n  });\n\n  <span class=\"hljs-keyword\">return<\/span> {\n    paths,\n\n    <span class=\"hljs-comment\">\/\/ All our news pages are pre-built and any path *not*<\/span>\n    <span class=\"hljs-comment\">\/\/ declared above results in a 404 (Not Found) error <\/span>\n    <span class=\"hljs-comment\">\/\/ page.<\/span>\n    <span class=\"hljs-attr\">fallback<\/span>: <span class=\"hljs-literal\">false<\/span>,\n  };\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_f4b1ba9e5a1bbec5679e7795627e7332\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Note that to generate <a href=\"https:\/\/nextjs.org\/docs\/api-reference\/data-fetching\/get-static-paths#paths\">paths<\/a> here, we need to tell Next.js what <code>locales<\/code> to build the paths from. You\u2019ll remember that we defined our locales in <code>next-i18next.config.js<\/code> and passed them on to Next\u2019s <code>next.config.js<\/code>. Next.js will, in turn, make these locales available to <code>getStaticPaths<\/code>. So, we will create a news article page for each of our configured supported locales, English (<code>en<\/code>) and Spanish (<code>es<\/code>).<\/p>\n<p>Now we also need to have the <a href=\"https:\/\/nextjs.org\/docs\/basic-features\/data-fetching\/get-static-props\">getStaticProps<\/a> function for (SSG), and it will look like this:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ pages\/news\/&#91;slug].js<\/span>\n\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> getStaticProps = <span class=\"hljs-keyword\">async<\/span> (context) =&gt; {\n  <span class=\"hljs-keyword\">const<\/span> { slug } = context.params;\n  <span class=\"hljs-keyword\">const<\/span> { locale } = context;\n\n  <span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">`http:\/\/localhost:3001\/<span class=\"hljs-subst\">${locale}<\/span>\/<span class=\"hljs-subst\">${slug}<\/span>`<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> res.json();\n\n  <span class=\"hljs-keyword\">return<\/span> {\n    <span class=\"hljs-attr\">props<\/span>: {\n      ...(<span class=\"hljs-keyword\">await<\/span> serverSideTranslations(locale, &#91;<span class=\"hljs-string\">'common'<\/span>])),\n      data,\n    },\n  };\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_3fe6ed10701f2bb626ef1f36aff16f77\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Here we get both the <code>slug<\/code> and <code>locale<\/code> from the params we added in the <code>getStaticPaths<\/code> function. We are using these values to <code>fetch<\/code> the news item\u2019s localized details from our mock backend. For example, hitting <code>http:\/\/localhost:3001\/es\/deliveroo-confirms-dutch-exit-next-month<\/code> would give us JSON that looked like the following.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">{\n  <span class=\"hljs-attr\">\"id\"<\/span>: <span class=\"hljs-number\">4<\/span>,\n  <span class=\"hljs-attr\">\"slug\"<\/span>: <span class=\"hljs-string\">\"deliveroo-confirms-dutch-exit-next-month\"<\/span>,\n  <span class=\"hljs-attr\">\"title\"<\/span>: <span class=\"hljs-string\">\"Deliveroo confirma su salida holandesa el pr\u00f3ximo mes\"<\/span>,\n  <span class=\"hljs-attr\">\"description\"<\/span>: <span class=\"hljs-string\">\"...\"<\/span>,\n  <span class=\"hljs-attr\">\"date\"<\/span>: <span class=\"hljs-string\">\"05 de marzo de 2022\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_42553d870852b8600e44646138186c8a\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Also, note that we are using <code>next-i18next<\/code>&#8216;s <code>serverSideTranslations<\/code> method the same way we did on our homepage, ensuring our translated UI strings are also available to our component during SSG.<\/p>\n<p>With that, we should be able to use the returned <code>data<\/code> from <code>getStaticProps<\/code> and render it in our JSX.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ pages\/news\/&#91;slug].js<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> { useTranslation } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next-i18next'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Link <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next\/link'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">NewsDetail<\/span>(<span class=\"hljs-params\">{ data }<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> { t } = useTranslation();\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Link<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">'\/'<\/span>&gt;<\/span>{t('homepage_nav_link_label')}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Link<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{data.date}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">article<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>{data.title}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{data.content}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">article<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> getStaticProps = <span class=\"hljs-keyword\">async<\/span> (context) =&gt; {\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> getStaticPaths = <span class=\"hljs-keyword\">async<\/span> ({ locales }) =&gt; {\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_67e421555520a8c8daa0e0ace0a04e12\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<h2><span class=\"ez-toc-section\" id=\"making-our-language-switcher-functional\"><\/span>Making our language switcher functional<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>To make our <code>LanguageSwitcher<\/code> component work as expected, we will need to use the <a href=\"https:\/\/nextjs.org\/docs\/api-reference\/next\/router#userouter\">useRouter<\/a> hook from the <code>next\/router<\/code> package.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ components\/LanguageSwitcher.jsx<\/span>\n\n<span class=\"hljs-keyword\">import<\/span> { useRouter } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'next\/router'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">LanguageSwitcher<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> router = useRouter();\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">select<\/span> <span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{(e)<\/span> =&gt;<\/span>\n          router.push(\n            {\n              pathname: router.pathname,\n              query: router.query,\n            },\n            null,\n            { locale: e.target.value }\n          )\n        }\n      &gt;\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">'en'<\/span>&gt;<\/span>English<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">'es'<\/span>&gt;<\/span>Espa\u00f1ol<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">select<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_78c1715fe72992c475b11c7abdffc573\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>The\u00a0<a href=\"https:\/\/nextjs.org\/docs\/api-reference\/next\/router#router-object\">router object<\/a>\u00a0returned by <code>useRouter<\/code> allows us to programmatically navigate to our localized routes with <code>router.push()<\/code>. On any given page, we want only want to change the locale part of the route when switching languages. For example, if we\u2019re on <code>\/news\/foo<\/code> (default English route), switching to Spanish should take us to <code>\/es\/news\/foo<\/code>. To accomplish this, we pass the router\u2019s <code>pathname<\/code> and <code>query<\/code> back to the router unchanged, only updating the <code>locale<\/code> to match the one the user selected from the drop-down.<\/p>\n<p>\ud83d\uddd2\ufe0f <em>Note \u00bb<\/em> The second argument to <code>router.push()<\/code> is an optional decorator called <code>as<\/code>. This can be used to set the value shown in the browser URL bar. (More info on that in the <a href=\"https:\/\/nextjs.org\/docs\/api-reference\/next\/router#routerpush\">router.push() documentation<\/a>.) We\u2019re not really using <code>as<\/code> here, so we pass in <code>null<\/code> for its value.<\/p>\n<p>With all that in place, your <code>LanguageSwitcher<\/code> component should work as expected. You can now read the news list on the homepage and click on each to get the news detail page in the default language. To read it in another language, you can change it from the drop-down and enjoy!<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-53275 aligncenter\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/05\/News-detail-page-translation.gif\" alt=\"News detail page translation | Phrase\" width=\"2000\" height=\"1984\" \/><\/p>\n<p>\ud83d\udd17 <em>Resource \u00bb<\/em> You can get the complete code of our demo app from <a href=\"https:\/\/github.com\/PhraseApp-Blog\/next-i18next-demo-2023\">our GitHub repo<\/a>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"ready-to-start-translating\"><\/span>Ready to start translating<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>We truly hope you enjoyed building a news reader app in Next.js with multilingual support. We used the next-i18next library for component-level string i18n configurations and tweaked our SSG code to generate localized pages, ensuring our pages load smoothly.<\/p>\n<p>If you\u2019re ready to level up your app translation process, check out the Phrase Localization Platform. With its dedicated software localization solution, <a href=\"https:\/\/phrase.com\/platform\/strings\/\">Phrase Strings<\/a>, you can manage translation strings for your web or mobile app more easily and efficiently than ever.<\/p>\n<p>With a robust API to automate translation workflows and integrations with GitHub, GitLab, Bitbucket, and other popular software platforms, Phrase Strings can do the heavy lifting for you to stay focused on your code.<\/p>\n<p>Phrase Strings provides a comprehensive strings editor that enables translators to access the content you have pushed for translation. Once the translation is complete, you can effortlessly retrieve the translated content and incorporate it back into your project.<\/p>\n<p>As your software product grows, our integrated suite will enable you to seamlessly connect Phrase Strings with a cutting-edge translation management system (TMS), so you can unlock the full power of traditional CAT tools and machine translation capabilities.<\/p>\n<p>Check out all\u00a0<a href=\"https:\/\/phrase.com\/roles\/developers\/\">Phrase features for developers<\/a> and see for yourself how they can streamline your software localization workflows from day one.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n\n<div id=\"acf\/blog-cta-block_f7bc380e6c8197e297fa1c10a3e250e7\" class=\"pxblock pxblock--blog-cta bg--green image--orientation-landscape\">\n\t<div class=\"block-container\">\n\t\t\t\t\t<div class=\"image image--align-middle\">\n\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1260\" height=\"992\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero.png\" class=\"attachment-original size-original\" alt=\"String Management UI visual | Phrase\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero.png 1260w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-300x236.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-1024x806.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-768x605.png 768w\" sizes=\"(max-width: 1260px) 100vw, 1260px\" \/>\t\t\t<\/div>\n\t\t\t\t<div class=\"content\">\n\t\t\t<p class=\"subhead\">Phrase Strings<\/p>\n<p class=\"secondary h6\">Take your web or mobile app global without any hassle<\/p>\n<div class=\"text--copy\">\n<p class=\"small\">Adapt your software, website, or video game for global audiences with the leanest and most realiable software localization platform.<\/p>\n<p><a class=\"btn btn--outline\" href=\"https:\/\/phrase.com\/platform\/strings\/\">Explore Phrase Strings<\/a><\/p>\n<\/div>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to build a news reader app in Next.js and level up your Next.js i18n skills to successfully launch in international markets.<\/p>\n","protected":false},"author":61,"featured_media":39386,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_stopmodifiedupdate":true,"_modified_date":"","_searchwp_excluded":"","footnotes":""},"categories":[40],"class_list":["post-53254","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software-localization"],"acf":[],"_links":{"self":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/53254"}],"collection":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/users\/61"}],"replies":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/comments?post=53254"}],"version-history":[{"count":40,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/53254\/revisions"}],"predecessor-version":[{"id":83799,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/53254\/revisions\/83799"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/media\/39386"}],"wp:attachment":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/media?parent=53254"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/categories?post=53254"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}