{"id":38624,"date":"2023-03-03T10:31:03","date_gmt":"2023-03-03T09:31:03","guid":{"rendered":"https:\/\/phrase.com\/?p=38624"},"modified":"2023-08-21T14:05:05","modified_gmt":"2023-08-21T12:05:05","slug":"python-localization","status":"publish","type":"post","link":"https:\/\/phrase.com\/blog\/posts\/python-localization\/","title":{"rendered":"The Ultimate Guide to Python Localization"},"content":{"rendered":"\n<div id=\"acf\/text-block_715ad151c0dfb2ba596c89474a09c4fa\" 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>Localizing Python applications is a process with many moving parts. But when done right, it can improve accessibility, increase user engagement, and expand market reach.<\/p>\n<p>To help you get started, this tutorial will outline best practices for preparing Python apps for localization using JSON or YAML files, and discuss common modules available to help.<\/p>\n<p>It will provide valuable insights for both developers looking to improve global appeal and businesses looking to expand into new markets.<\/p>\n<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\/python-localization\/#how-do-i-internationalize-ui-strings-with-python\" title=\"How do I internationalize UI strings with Python?\">How do I internationalize UI strings with Python?<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#why-do-we-use-translation-files-for-our-ui\" title=\"Why do we use translation files for our UI?\">Why do we use translation files for our UI?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#installation\" title=\"Installation\">Installation<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-to-load-json-translation-files\" title=\"How to load JSON translation files?\">How to load JSON translation files?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-to-load-yaml-translation-files\" title=\"How to load YAML translation files?\">How to load YAML translation files?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#translator-class\" title=\"Translator class\">Translator class<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#adding-interpolation-to-the-translator-class\" title=\"Adding interpolation to the Translator class\">Adding interpolation to the Translator class<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#adding-pluralization-to-the-translator-class\" title=\"Adding pluralization to the Translator class\">Adding pluralization to the Translator class<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#using-the-translator-module-in-your-application\" title=\"Using the Translator module in your application\">Using the Translator module in your application<\/a><\/li><\/ul><\/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\/python-localization\/#how-do-i-internationalize-my-python-ui-with-gettext\" title=\"How do I internationalize my Python UI with gettext?\">How do I internationalize my Python UI with gettext?<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#basic-translation-messages\" title=\"Basic translation messages\">Basic translation messages<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#adding-string-interpolation-via-gettext\" title=\"Adding string interpolation via gettext\">Adding string interpolation via gettext<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#adding-pluralization-support-via-ngettext\" title=\"Adding pluralization support via ngettext\">Adding pluralization support via ngettext<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#using-gettext-in-your-application\" title=\"Using gettext in your application\">Using gettext in your application<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-can-a-python-app-support-right-to-left-languages\" title=\"How can a Python app support right-to-left languages?\">How can a Python app support right-to-left languages?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-do-i-format-localized-dates-and-times-in-python\" title=\"How do I format localized dates and times in Python?\">How do I format localized dates and times in Python?<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-do-i-work-with-date-and-time-duration\" title=\"How do I work with date and time duration?\">How do I work with date and time duration?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-18\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-can-i-use-datetimes\" title=\"How can I use datetimes?\">How can I use datetimes?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-19\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-do-i-format-localized-dates-with-babel\" title=\"How do I format localized dates with Babel?\">How do I format localized dates with Babel?<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-20\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-do-i-format-localized-numbers-in-python\" title=\"How do I format localized numbers in Python?\">How do I format localized numbers in Python?<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-21\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-do-i-use-the-built-in-locale-module-to-format-numbers\" title=\"How do I use the built-in locale module to format numbers?\">How do I use the built-in locale module to format numbers?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-22\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-do-i-use-babel-to-format-localized-numbers\" title=\"How do I use babel to format localized numbers?\">How do I use babel to format localized numbers?<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-23\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-do-i-format-localized-currency-in-python\" title=\"How do I format localized currency in Python?\">How do I format localized currency in Python?<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-24\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-do-i-use-the-built-in-locale-module-to-format-currency\" title=\"How do I use the built-in locale module to format currency?\">How do I use the built-in locale module to format currency?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-25\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#how-do-i-use-babel-to-format-localized-currency\" title=\"How do I use Babel to format localized currency?\">How do I use Babel to format localized currency?<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-26\" href=\"https:\/\/phrase.com\/blog\/posts\/python-localization\/#wrapping-up\" title=\"Wrapping up\">Wrapping up<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"how-do-i-internationalize-ui-strings-with-python\"><\/span>How do I internationalize UI strings with Python?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Let&#8217;s address some key questions on how best to prepare your Python app for localization.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"why-do-we-use-translation-files-for-our-ui\"><\/span>Why do we use translation files for our UI?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>There are a couple of benefits to using translation files instead of hard-coding translation texts in your application:<\/p>\n<ul>\n<li>It is easier to edit and translate as most translators are not familiar with code<\/li>\n<li>You can easily identify the wrong translation texts without searching through your code base<\/li>\n<li>There is no need to rebuild your applications when there is a change to a translation (depending on programming languages and frameworks used)<\/li>\n<\/ul>\n<p>At its core, translation files can be represented in different formats. The following section covers how to internationalize your Python application using:<\/p>\n<ul>\n<li>Custom implementation with JSON \/ YAML as translation files<\/li>\n<li><code>babel<\/code> and <code>gettext<\/code> to work with PO and MO translation files<\/li>\n<\/ul>\n<h3><span class=\"ez-toc-section\" id=\"installation\"><\/span>Installation<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Before that, let&#8217;s install the following Python packages:<\/p>\n<ul>\n<li><code>babel<\/code>: utilities for internationalization and localization in Python<\/li>\n<li><code>pyyaml<\/code>: support reading and writing of YAML files<\/li>\n<\/ul>\n<p>We can run the following commands from the command line to install our packages.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">pip install pyyaml\npip install babel<\/code><\/span><\/pre>\n\n\n<div id=\"acf\/text-block_c22e53f9c78fe027c83929581ae8b0f0\" 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<h3><span class=\"ez-toc-section\" id=\"how-to-load-json-translation-files\"><\/span>How to load JSON translation files?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>One of the simplest methods to store translation files is via JSON. For example, you can create a new file called <code>en.json<\/code> with the following items:<\/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=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">{\n    <span class=\"hljs-attr\">\"title\"<\/span>: <span class=\"hljs-string\">\"Dialogstation\"<\/span>,\n    <span class=\"hljs-attr\">\"ques-name\"<\/span>: <span class=\"hljs-string\">\"Geben Sie Ihren Namen ein:\"<\/span>,\n    <span class=\"hljs-attr\">\"ques-age\"<\/span>: <span class=\"hljs-string\">\"Geben Sie Ihr Alter ein:\"<\/span>,\n    <span class=\"hljs-attr\">\"ans-name\"<\/span>: <span class=\"hljs-string\">\"Hallo, $name! Willkommen bei Phrase\"<\/span>,\n    <span class=\"hljs-attr\">\"ans-age\"<\/span>: {\n        <span class=\"hljs-attr\">\"one\"<\/span>: <span class=\"hljs-string\">\"Du bist $count Jahr alt\"<\/span>,\n        <span class=\"hljs-attr\">\"other\"<\/span>: <span class=\"hljs-string\">\"Du bist $count Jahre alt\"<\/span>\n    },\n    <span class=\"hljs-attr\">\"ques-dob\"<\/span>: <span class=\"hljs-string\">\"Geben Sie Ihr Geburtsdatum ein (JJJJ-MM-TT):\"<\/span>,\n    <span class=\"hljs-attr\">\"ans-dob\"<\/span>: <span class=\"hljs-string\">\"Sie wurden am $dob geboren\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><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_896f2a9fca5e7251f87d4c0c1a27ff1a\" 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>Then, simply load it using the built-in <code>json<\/code> package as follows:<\/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-keyword\">import<\/span> json\n\n<span class=\"hljs-keyword\">with<\/span> open(<span class=\"hljs-string\">'filename.json'<\/span>, <span class=\"hljs-string\">'r'<\/span>, encoding=<span class=\"hljs-string\">'utf8'<\/span>) <span class=\"hljs-keyword\">as<\/span> f:\n    data = json.load(f)<\/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_b47374fc0874e2407742f64b3bcadb41\" 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<h3><span class=\"ez-toc-section\" id=\"how-to-load-yaml-translation-files\"><\/span>How to load YAML translation files?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>We can use YAML files instead of JSON. We will need the <code>pyyaml<\/code> package to support YAML.<\/p>\n<p>Given <code>en.yaml<\/code> as the translation file for English with the following content:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">title: Interactive Terminal\nques-name: <span class=\"hljs-string\">\"Enter your name:\"<\/span>\nques-age: <span class=\"hljs-string\">\"Enter your age:\"<\/span>\nans-name: Hello, $name! Welcome to Phrase\nans-age:\n  one: You are $count year old\n  other: You are $count years old\nques-dob: <span class=\"hljs-string\">\"Enter your date of birth (YYYY-MM-DD):\"<\/span>,\nans-dob: You were born on $dob<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_db20bb7b63389f1c30d4aaa96d618a80\" 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>Likewise, the German translation file should be called <code>de.yaml<\/code>:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">title: Dialogstation\nques-name: <span class=\"hljs-string\">\"Geben Sie Ihren Namen ein:\"<\/span>\nques-age: <span class=\"hljs-string\">\"Geben Sie Ihr Alter ein:\"<\/span>\nans-name: Hallo, $name! Willkommen bei Phrase\nans-age:\n  one: Du bist $count Jahr alt\n  other: Du bist $count Jahre alt\nques-dob: <span class=\"hljs-string\">\"Geben Sie Ihr Geburtsdatum ein (JJJJ-MM-TT):\"<\/span>,\nans-dob: Sie wurden am $dob geboren<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_d849f1b908cd749433722d963e3cd21b\" 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>Load it using <code>pyyaml<\/code> package as follows:<\/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=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> yaml\n\n<span class=\"hljs-keyword\">with<\/span> open(<span class=\"hljs-string\">'filename.yml'<\/span>, <span class=\"hljs-string\">'r'<\/span>, encoding=<span class=\"hljs-string\">'utf8'<\/span>) <span class=\"hljs-keyword\">as<\/span> f:\n    data = yaml.safe_load(f)<span class=\"hljs-keyword\">import<\/span> json<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><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_cadeeb70c8fc2a7834f4f485b4153bd9\" 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<h3><span class=\"ez-toc-section\" id=\"translator-class\"><\/span>Translator class<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Using what you have learned so far, let\u2019s build a custom module with a <code>Translator<\/code> class with the following features:<\/p>\n<ul>\n<li>Load translation files during startup<\/li>\n<li>Set the currently active locale<\/li>\n<li>Set the plural rules<\/li>\n<li>Translate and format the translation text<\/li>\n<\/ul>\n<p>In addition, the module should also include 2 additional functions to:<\/p>\n<ul>\n<li>Convert a string to a datetime object<\/li>\n<li>Format a datetime object to a string<\/li>\n<\/ul>\n<p>Make sure that your file structure is as follows:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">.\n\u251c\u2500\u2500 data (folder containing JSON or YAML translation files)\/\n\u2502   \u251c\u2500\u2500 en.json\n\u2502   \u251c\u2500\u2500 de.json\n\u2502   \u251c\u2500\u2500 en.yaml\n\u2502   \u2514\u2500\u2500 de.yaml\n\u251c\u2500\u2500 i18n.py (custom module)\n\u2514\u2500\u2500 main.py (main application)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_8f50d241343d73350c5025a8dc5518b0\" 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>Create a new Python file called <code>i18n.py<\/code> with the following code:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">import json\nimport glob\nimport os\nimport yaml\nfrom datetime import datetime\nfrom babel.dates import format_datetime\n\nsupported_format = &#91;'json', 'yaml']\n\n\nclass Translator():\n    def __init__(self, translations_folder, file_format='json', default_locale='en'):\n        # initialization\n        self.data = {}\n        self.locale = 'en'\n\n        # check if format is supported\n        if file_format in supported_format:\n            # get list of files with specific extensions\n            files = glob.glob(os.path.join(translations_folder, f'*.{file_format}'))\n            for fil in files:\n                # get the name of the file without extension, will be used as locale name\n                loc = os.path.splitext(os.path.basename(fil))&#91;0]\n                with open(fil, 'r', encoding='utf8') as f:\n                    if file_format == 'json':\n                        self.data&#91;loc] = json.load(f)\n                    elif file_format == 'yaml':\n                        self.data&#91;loc] = yaml.safe_load(f)\n\n    def set_locale(self, loc):\n        if loc in self.data:\n            self.locale = loc\n        else:\n            print('Invalid locale')\n\n    def get_locale(self):\n        return self.locale\n\n    def translate(self, key):\n        # return the key instead of translation text if locale is not supported\n        if self.locale not in self.data:\n            return key\n\n        text = self.data&#91;self.locale].get(key, key)\n        \n        return text\n\n\ndef str_to_datetime(dt_str, format='%Y-%m-%d'):\n    return datetime.strptime(dt_str, format)\n\n\ndef datetime_to_str(dt, format='MMMM dd, yyyy', loc='en'):\n    return format_datetime(dt, format=format, locale=loc)<\/code><\/span><\/pre>\n\n\n<div id=\"acf\/text-block_0ebf9c493238fb6472bbbba46e38196a\" 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 <code>glob<\/code> module is used to load the translation files dynamically depending on the <code>file_format<\/code> value. It accepts either <code>json<\/code> or <code>yaml<\/code>:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">    def __init__(<span class=\"hljs-keyword\">self<\/span>, folder, file_format=<span class=\"hljs-string\">'json'<\/span>, default_locale=<span class=\"hljs-string\">'en'<\/span>, default_locale=<span class=\"hljs-string\">'en'<\/span>):\n        <span class=\"hljs-comment\"># ...<\/span>\n\n        <span class=\"hljs-comment\"># check if format is supported<\/span>\n        <span class=\"hljs-keyword\">if<\/span> file_format in supported_format:\n            <span class=\"hljs-comment\"># get list of files with specific extensions<\/span>\n            files = glob.glob(os.path.join(folder, f<span class=\"hljs-string\">'*.{file_format}'<\/span>))\n            <span class=\"hljs-keyword\">for<\/span> fil in files:\n                <span class=\"hljs-comment\"># get the name of the file without extension, will be used as locale name<\/span>\n                loc = os.path.splitext(os.path.basename(fil))&#91;<span class=\"hljs-number\">0<\/span>]\n                with open(fil, <span class=\"hljs-string\">'r'<\/span>, encoding=<span class=\"hljs-string\">'utf8'<\/span>) <span class=\"hljs-keyword\">as<\/span> f:\n                    <span class=\"hljs-keyword\">if<\/span> file_format == <span class=\"hljs-string\">'json'<\/span>:\n                        <span class=\"hljs-keyword\">self<\/span>.data&#91;loc] = json.load(f)\n                    elif file_format == <span class=\"hljs-string\">'yaml'<\/span>:\n                        <span class=\"hljs-keyword\">self<\/span>.data&#91;loc] = yaml.safe_load(f)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_0c081c093a18a006e7e495b33d7186f6\" 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 core feature is the <code>translate<\/code> function which returns the translation text based on the current active locale:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">    def translate(<span class=\"hljs-keyword\">self<\/span>, key):\n        <span class=\"hljs-comment\"># return the key instead<\/span>\n        <span class=\"hljs-keyword\">if<\/span> <span class=\"hljs-keyword\">self<\/span>.locale not in <span class=\"hljs-keyword\">self<\/span>.data:\n            <span class=\"hljs-keyword\">return<\/span> key\n\n        text = <span class=\"hljs-keyword\">self<\/span>.data&#91;<span class=\"hljs-keyword\">self<\/span>.locale].get(key, key)\n\n        <span class=\"hljs-keyword\">return<\/span> text<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_60a902a9bf9db47386dcc9550ee690eb\" 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 module also contains 2 additional global functions for datetime formatting:<\/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=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">def str_to_datetime(dt_str, format=<span class=\"hljs-string\">'%Y-%m-%d'<\/span>):\n    <span class=\"hljs-keyword\">return<\/span> datetime.strptime(dt_str, format)\n\ndef datetime_to_str(dt, format=<span class=\"hljs-string\">'MMMM dd, yyyy'<\/span>, loc=<span class=\"hljs-string\">'en'<\/span>):\n    <span class=\"hljs-keyword\">return<\/span> format_datetime(dt, format=format, locale=loc)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><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_1ad8e57dfc34195e83e63719f5498345\" 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<h3><span class=\"ez-toc-section\" id=\"adding-interpolation-to-the-translator-class\"><\/span>Adding interpolation to the Translator class<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>For string interpolation, you can use the built-in template string module. Add the following import statement:<\/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=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">from<\/span> string <span class=\"hljs-keyword\">import<\/span> Template<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><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_3d5621858b33f86aa3d7dc04abb3e463\" 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>Under the <code>translate<\/code> function, instead of returning the <code>text<\/code> variable directly, instantiate it with the <code>Template<\/code> class and call the <code>safe_substitute<\/code> function as follows:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">def translate(<span class=\"hljs-keyword\">self<\/span>, key, **kwargs):\n    <span class=\"hljs-comment\"># return the key instead of translation text if locale is not supported<\/span>\n    <span class=\"hljs-keyword\">if<\/span> <span class=\"hljs-keyword\">self<\/span>.locale not in <span class=\"hljs-keyword\">self<\/span>.data:\n        <span class=\"hljs-keyword\">return<\/span> key\n\n    text = <span class=\"hljs-keyword\">self<\/span>.data&#91;<span class=\"hljs-keyword\">self<\/span>.locale].get(key, key)\n    \n    <span class=\"hljs-comment\"># string interpolation<\/span>\n    <span class=\"hljs-keyword\">return<\/span> Template(text).safe_substitute(**kwargs)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_2c86d576d39cbab884a0a9a248b1cd12\" 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<h3><span class=\"ez-toc-section\" id=\"adding-pluralization-to-the-translator-class\"><\/span>Adding pluralization to the Translator class<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>You can import the <code>babel.plural.PluralRule<\/code> class for pluralization support:<\/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-keyword\">from<\/span>\u00a0babel.plural\u00a0<span class=\"hljs-keyword\">import<\/span>\u00a0PluralRule<\/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_1e2f69909bd36263938b3af5b74d35c7\" 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>Under the <code>__init__<\/code> function, initialize a new<code> plural_rule<\/code> variable as follows:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">    def __init__(<span class=\"hljs-keyword\">self<\/span>, folder, file_format=<span class=\"hljs-string\">'json'<\/span>, default_locale=<span class=\"hljs-string\">'en'<\/span>):\n        <span class=\"hljs-keyword\">self<\/span>.data = {}\n        <span class=\"hljs-keyword\">self<\/span>.locale = default_locale\n        <span class=\"hljs-keyword\">self<\/span>.plural_rule = PluralRule({<span class=\"hljs-string\">'one'<\/span>: <span class=\"hljs-string\">'n is <\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_d33814e7ad1ee30c122868ccaca4c7c7\" 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\uddd2 <em>Note \u00bb<\/em> The module uses <code>{'one': 'n is 1'}<\/code> as the <a href=\"https:\/\/babel.pocoo.org\/en\/latest\/api\/plural.html#module-babel.plural\">plural rule<\/a>, which represents simple pluralization. The key should be one of the following:<\/p>\n<ul>\n<li>0<\/li>\n<li>1<\/li>\n<li>2<\/li>\n<li>a few<\/li>\n<li>many<\/li>\n<li>other<\/li>\n<\/ul>\n<p>\ud83d\udd17 <em>Resource \u00bb<\/em> The pluralization syntax is based on the <a href=\"https:\/\/www.unicode.org\/reports\/tr35\/tr35-33\/tr35-numbers.html#Language_Plural_Rules\">CDLR rules<\/a>.<\/p>\n<p>Next, implement the setter and getter function for the plural rule in the <code>Translator<\/code> class:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">class\u00a0Translator():\n    ...\n\n    def set_locale(self, loc):\n        if loc in self.data:\n            self.locale = loc\n        else:\n            print('Invalid locale')\n\n    def get_locale(self):\n        return self.locale\n\n    def set_plural_rule(self, rule):\n        try:\n            self.plural_rule = PluralRule(rule)\n        except Exception:\n            print('Invalid plural rule')\n\n    def get_plural_rule(self):\n        return self.plural_rule<\/code><\/span><\/pre>\n\n\n<div id=\"acf\/text-block_a0b568e2dc9ed65608d4cb94e4a6a13e\" 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>Modify the code under the <code>translate<\/code> function to include a check for pluralization:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">class Translator():\n    ...\n\n    def translate(self, key, **kwargs):\n        # return the key instead of translation text if locale is not supported\n        if self.locale not in self.data:\n            return key\n\n        text = self.data&#91;self.locale].get(key, key)\n\n        # type dict represents key with plural form\n        if type(text) == dict:\n            count = kwargs.get('count', 1)\n        # parse count to int\n        try:\n            count = int(count)\n        except Exception:\n            print('Invalid count')\n            return key\n\n        text = text.get(self.plural_rule(count), key)\n        return Template(text).safe_substitute(**kwargs)<\/code><\/span><\/pre>\n\n\n<div id=\"acf\/text-block_c6367f5883ac2eaddf543a3c50de7f8c\" 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 complete code for the <code>Translator<\/code> class is as follows:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">from babel.plural import PluralRule\nimport json\nfrom string import Template\nimport glob\nimport os\nimport yaml\nfrom datetime import datetime\nfrom babel.dates import format_datetime\n\nsupported_format = &#91;'json', 'yaml']\n\n\nclass Translator():\n    def __init__(self, translations_folder, file_format='json', default_locale='en'):\n        # initialization\n        self.data = {}\n        self.locale = 'en'\n        self.plural_rule = PluralRule({'one': 'n is 1'})\n\n        # check if format is supported\n        if file_format in supported_format:\n            # get list of files with specific extensions\n            files = glob.glob(os.path.join(translations_folder, f'*.{file_format}'))\n            for fil in files:\n                # get the name of the file without extension, will be used as locale name\n                loc = os.path.splitext(os.path.basename(fil))&#91;0]\n                with open(fil, 'r', encoding='utf8') as f:\n                    if file_format == 'json':\n                        self.data&#91;loc] = json.load(f)\n                    elif file_format == 'yaml':\n                        self.data&#91;loc] = yaml.safe_load(f)\n\n    def set_locale(self, loc):\n        if loc in self.data:\n            self.locale = loc\n        else:\n            print('Invalid locale')\n\n    def get_locale(self):\n        return self.locale\n\n    def set_plural_rule(self, rule):\n        try:\n            self.plural_rule = PluralRule(rule)\n        except Exception:\n            print('Invalid plural rule')\n\n    def get_plural_rule(self):\n        return self.plural_rule\n\n    def translate(self, key, **kwargs):\n        # return the key instead of translation text if locale is not supported\n        if self.locale not in self.data:\n            return key\n\n        text = self.data&#91;self.locale].get(key, key)\n        # type dict represents key with plural form\n        if type(text) == dict:\n            count = kwargs.get('count', 1)\n            # parse count to int\n            try:\n                count = int(count)\n            except Exception:\n                print('Invalid count')\n                return key\n            text = text.get(self.plural_rule(count), key)\n        return Template(text).safe_substitute(**kwargs)\n\n\ndef parse_datetime(dt, input_format='%Y-%m-%d', output_format='MMMM dd, yyyy', output_locale='en'):\n    dt = datetime.strptime(dt, input_format)\n    return format_datetime(dt, format=output_format, locale=output_locale)<\/code><\/span><\/pre>\n\n\n<div id=\"acf\/text-block_e16af4203c6c8e58cd867f1d670516c1\" 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<h3><span class=\"ez-toc-section\" id=\"using-the-translator-module-in-your-application\"><\/span>Using the Translator module in your application<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Now, you can use the <code>Translator<\/code> class as a module in your application. Have a look at the following code snippet as a reference for the basic usage of the custom <code>Translator<\/code> module:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># import the module<\/span>\nimport i18n\n\n<span class=\"hljs-comment\"># instantiate a new Translator class with the path to the data<\/span>\ntranslator = i18n.Translator(<span class=\"hljs-string\">'data\/'<\/span>)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">name = <span class=\"hljs-string\">'John Doe'<\/span>\n<span class=\"hljs-keyword\">print<\/span>(translator.translate(<span class=\"hljs-string\">'ans-name'<\/span>, name=name))\n<span class=\"hljs-comment\"># Hello, John Doe! Welcome to Phrase<\/span>\n\n<span class=\"hljs-comment\"># change the active locale to de<\/span>\ntranslator.set_locale(<span class=\"hljs-string\">'de'<\/span>)\n<span class=\"hljs-keyword\">print<\/span>(translator.translate(<span class=\"hljs-string\">'ans-name'<\/span>, name=name))\n<span class=\"hljs-comment\"># Hallo, John Doe! Willkommen bei Phrase<\/span>\n\nage = <span class=\"hljs-number\">30<\/span>\n<span class=\"hljs-keyword\">print<\/span>(translator.translate(<span class=\"hljs-string\">'ans-age'<\/span>, count=age))\n<span class=\"hljs-comment\"># Du bist 30 Jahre alt<\/span>\n\ndob = <span class=\"hljs-string\">'1992-01-01'<\/span>\ndob = i18n.parse_datetime(dob)\n\n<span class=\"hljs-keyword\">print<\/span>(translator.translate(<span class=\"hljs-string\">'ans-dob'<\/span>, dob=dob))\n<span class=\"hljs-comment\"># Sie wurden am January 01, 1992 geboren<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_f09c70e10b2b5a5bbb316d5dce6d9bcd\" 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>You can easily extend the functionality of the <code>i18n<\/code> module to support more features based on your requirements.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"how-do-i-internationalize-my-python-ui-with-gettext\"><\/span>How do I internationalize my Python UI with gettext?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Alternatively, you can utilize the <code>gettext<\/code> module to internationalize Python applications. <code>gettext<\/code> uses PO (also known as POT) and MO message catalog files.<\/p>\n<p>\ud83d\uddd2 <em>Note \u00bb<\/em> PO files represent the human-editable translation files, while MO files are machine-readable for consumption by <code>gettext<\/code>.<\/p>\n<p>Fortunately, the <code>babel<\/code> package complements nicely with the <code>gettext<\/code> module. <code>babel<\/code> provides the following utility functions for working with Message Catalogs:<\/p>\n<ul>\n<li><code>extract<\/code>: extract messages from source files to generate a POT file<\/li>\n<li><code>init<\/code>: create new message catalogs from a POT file<\/li>\n<li><code>update<\/code>: update existing message catalogs in a POT file<\/li>\n<li><code>compile<\/code>: compile POT files to MO files<\/li>\n<\/ul>\n<h3><span class=\"ez-toc-section\" id=\"basic-translation-messages\"><\/span>Basic translation messages<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>The first phase is to mark strings as translatable in the source files. Simply enclose translatable strings with the <code>_()<\/code> function:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># unmarked strings<\/span>\n<span class=\"hljs-keyword\">print<\/span>(<span class=\"hljs-string\">'Interactive Terminal'<\/span>)\n<span class=\"hljs-keyword\">print<\/span>(<span class=\"hljs-string\">'title'<\/span>)\n\n<span class=\"hljs-comment\"># strings marked as translatable<\/span>\n<span class=\"hljs-keyword\">print<\/span>(_(<span class=\"hljs-string\">'Interactive Terminal'<\/span>))\n<span class=\"hljs-keyword\">print<\/span>(_(<span class=\"hljs-string\">'title'<\/span>))<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_287c657334200c9a948246355e57d310\" 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\uddd2 <em>Note \u00bb<\/em> <code>_()<\/code> is a short-hand alias of <code>gettext.gettext()<\/code> function. You can pass in the key for translation or the actual translation string as long as it is unique across the application. It will return the translated string based on the current locale.<\/p>\n<p>For example, given that the code above resides in a Python file called <code>main_babel.py<\/code>, the command to extract messages from source files is as follows:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">pybabel extract -o data\/messages.pot main_babel.py<\/code><\/span><\/pre>\n\n\n<div id=\"acf\/text-block_cb3fc67e6bd28ba8cd29fb268dba5123\" 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 output file, <code>data\/messages.pot<\/code>, should contain the following content:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">    msgid <span class=\"hljs-string\">\"\"<\/span>\n    msgstr <span class=\"hljs-string\">\"\"<\/span>\n    <span class=\"hljs-string\">\"Project-Id-Version: PROJECT VERSION\\n\"<\/span>\n    <span class=\"hljs-string\">\"Report-Msgid-Bugs-To: EMAIL@ADDRESS\\n\"<\/span>\n    <span class=\"hljs-string\">\"POT-Creation-Date: 2022-06-17 23:04+0800\\n\"<\/span>\n    <span class=\"hljs-string\">\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"<\/span>\n    <span class=\"hljs-string\">\"Last-Translator: FULL NAME &amp;lt;EMAIL@ADDRESS&amp;gt;\\n\"<\/span>\n    <span class=\"hljs-string\">\"Language-Team: LANGUAGE &amp;lt;LL@li.org&amp;gt;\\n\"<\/span>\n    <span class=\"hljs-string\">\"MIME-Version: 1.0\\n\"<\/span>\n    <span class=\"hljs-string\">\"Content-Type: text\/plain; charset=utf-8\\n\"<\/span>\n    <span class=\"hljs-string\">\"Content-Transfer-Encoding: 8bit\\n\"<\/span>\n    <span class=\"hljs-string\">\"Generated-By: Babel 2.10.1\\n\"<\/span>\n\n    <span class=\"hljs-comment\">#: main_babel.py:11<\/span>\n    msgid <span class=\"hljs-string\">\"title\"<\/span>\n    msgstr <span class=\"hljs-string\">\"\"<\/span>\n\n    <span class=\"hljs-comment\">#: main_babel.py:14<\/span>\n    msgid <span class=\"hljs-string\">\"ques-name\"<\/span>\n    msgstr <span class=\"hljs-string\">\"\"<\/span>\n\n    <span class=\"hljs-comment\">#<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_8e8af76d00a929d2cc529bb5f2acbac5\" 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 represents the base translation file. <code>msgid<\/code> is the unique identifier for each message to be translated, while <code>msgstr<\/code> represents the translation text. You can leave <code>msgstr<\/code> empty for now as the actual translation text should be in the PO files.<\/p>\n<p>The <code>babel<\/code> module will generate the relevant files for each locale automatically for you during the initialization phase. Let\u2019s test it by running the following command for the <code>en<\/code> locale.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">pybabel init -l en -i data\/messages.pot -d data\/<\/code><\/span><\/pre>\n\n\n<div id=\"acf\/text-block_52366e47ddfbc05d9f8ad022ef360334\" 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\uddd2 <em>Note \u00bb<\/em> -l sets the locale for the generated PO files.<\/p>\n<p>Run another command again for <code>de<\/code> locale.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">pybabel init -l de -i data\/messages.pot -d data\/<\/code><\/span><\/pre>\n\n\n<div id=\"acf\/text-block_cc03bab298306fbe120cef53df486ecf\" 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 content inside each <code>messages.po<\/code> file should be the same as the base POT file. The next step is to fill in the corresponding translation text inside the PO files:<\/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=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">.\n\u251c\u2500\u2500 messages.pot\n\u251c\u2500\u2500 de\/\n\u2502   \u2514\u2500\u2500 LC_MESSAGES\/\n\u2502       \u2514\u2500\u2500 messages.po\n\u2514\u2500\u2500 en\/\n    \u2514\u2500\u2500 LC_MESSAGES\/\n        \u2514\u2500\u2500 messages.po<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_1887b7872349e8344405f1b4a7c0b123\" 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\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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">#: main_babel.py:11<\/span>\nmsgid <span class=\"hljs-string\">\"title\"<\/span>\nmsgstr <span class=\"hljs-string\">\"Interactive Terminal\"<\/span>\n\n<span class=\"hljs-comment\">#: main_babel.py:14<\/span>\nmsgid <span class=\"hljs-string\">\"ques-name\"<\/span>\nmsgstr <span class=\"hljs-string\">\"Enter your name:\"<\/span>\n\n<span class=\"hljs-comment\">#: main_babel.py:16<\/span>\nmsgid <span class=\"hljs-string\">\"ans-name\"<\/span>\nmsgstr <span class=\"hljs-string\">\"Hello, {name}! Welcome to Phrase\"<\/span>\n\n<span class=\"hljs-comment\">#: main_babel.py:19<\/span>\nmsgid <span class=\"hljs-string\">\"ques-age\"<\/span>\nmsgstr <span class=\"hljs-string\">\"Enter your age:\"<\/span>\n\n<span class=\"hljs-comment\">#: main_babel.py:21<\/span>\nmsgid <span class=\"hljs-string\">\"ans-age\"<\/span>\nmsgid_plural <span class=\"hljs-string\">\"ans-age-plural\"<\/span>\nmsgstr&#91;<span class=\"hljs-number\">0<\/span>] <span class=\"hljs-string\">\"You are {count} year old\"<\/span>\nmsgstr&#91;<span class=\"hljs-number\">1<\/span>] <span class=\"hljs-string\">\"You are {count} years old\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_47a100c3298348c7f6f3967f764070a1\" 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>Finally, run the following command to compile PO files into MO files:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">pybabel compile -d data\/<\/code><\/span><\/pre>\n\n\n<div id=\"acf\/text-block_35c1deb3ee99ea27702a7569dcbcd397\" 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 <code>data<\/code> folder should be as follows:<\/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=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">.\n\u251c\u2500\u2500 messages.pot\n\u251c\u2500\u2500 de\/\n\u2502   \u2514\u2500\u2500 LC_MESSAGES\/\n\u2502       \u251c\u2500\u2500 messages.mo\n\u2502       \u2514\u2500\u2500 messages.po\n\u2514\u2500\u2500 en\/\n    \u2514\u2500\u2500 LC_MESSAGES\/\n        \u251c\u2500\u2500 messages.mo\n        \u2514\u2500\u2500 messages.po<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_25438a3ee8e0546c5f901a39b04648bb\" 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>Once you are done with it, you can utilize the <code>gettext.translation<\/code> function to load the translation files.<\/p>\n<p>For example, you can call the <code>install<\/code> function to set it as the currently active locale and get the translation text as follows:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">import gettext\n\n<span class=\"hljs-comment\"># initialization<\/span>\nlang_en = gettext.translation(<span class=\"hljs-string\">'messages'<\/span>, localedir=<span class=\"hljs-string\">'data'<\/span>, languages=&#91;<span class=\"hljs-string\">'en'<\/span>])\n\n<span class=\"hljs-comment\"># set current locale to en<\/span>\nlang_en.install()\n\n<span class=\"hljs-keyword\">print<\/span>(_(<span class=\"hljs-string\">'ans-name'<\/span>))\n<span class=\"hljs-comment\"># Hello, John! Welcome to Phrase<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_e1dd111e06f2abe1a4125f996e9be545\" 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\uddd2 <em>Note \u00bb<\/em> The install function will import the <code>_()<\/code> alias internally. Hence, there is no need to import <code>_<\/code> manually.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"adding-string-interpolation-via-gettext\"><\/span>Adding string interpolation via gettext<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>For string interpolation, you can use a variable name and mark it with curly brackets. For example, given the following translation text:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">#: main_babel.py:16<\/span>\nmsgid <span class=\"hljs-string\">\"ans-name\"<\/span>\nmsgstr <span class=\"hljs-string\">\"Hello, {name}! Welcome to Phrase\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_2d07f54e196bd167c046c7d222899455\" 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\uddd2 <em>Note \u00bb<\/em> Using curly brackets <code>{variable_name}<\/code> in the translation text allows string interpolation with the <code>format<\/code> function.<\/p>\n<p>You can easily interpolate in the translation text as follows:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">import gettext\n\n<span class=\"hljs-comment\"># initialization<\/span>\nlang_en = gettext.translation(<span class=\"hljs-string\">'messages'<\/span>, localedir=<span class=\"hljs-string\">'data'<\/span>, languages=&#91;<span class=\"hljs-string\">'en'<\/span>])\n\n<span class=\"hljs-comment\"># set current locale to en<\/span>\nlang_en.install()\n\n<span class=\"hljs-keyword\">print<\/span>(_(<span class=\"hljs-string\">'ans-name'<\/span>).format(name=<span class=\"hljs-string\">'John'<\/span>))\n<span class=\"hljs-comment\"># Hello, John! Welcome to Phrase<\/span>\n\n<span class=\"hljs-keyword\">print<\/span>(_(<span class=\"hljs-string\">'ans-name'<\/span>).format(name=<span class=\"hljs-string\">'Kelly'<\/span>))\n<span class=\"hljs-comment\"># Hello, Kelly! Welcome to Phrase<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_648cf34d49730525fa90a5182143eebc\" 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<h3><span class=\"ez-toc-section\" id=\"adding-pluralization-support-via-ngettext\"><\/span>Adding pluralization support via ngettext<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>For pluralization support, use the <code>ngettext<\/code> function instead. It accepts 3 input arguments:<\/p>\n<ul>\n<li><code>singular<\/code>: id for singular form<\/li>\n<li><code>plural<\/code>: id for plural form<\/li>\n<li><code>n<\/code>: plural determiner<\/li>\n<\/ul>\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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">print<\/span>(ngettext(<span class=\"hljs-string\">'ans-age'<\/span>, <span class=\"hljs-string\">'ans-age-plural'<\/span>, age))<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_abd54c2010dd7e28203a76dc5a946fb4\" 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>Just like the <code>gettext<\/code> function, <code>ngettext<\/code> will return the translated string. You can easily interpolate in the output string with a function like <code>format<\/code>:<\/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=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">print<\/span>(ngettext(<span class=\"hljs-string\">'ans-age'<\/span>, <span class=\"hljs-string\">'ans-age-plural'<\/span>, age).format(count=age))<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_64a528a3b9037cd6b062d5267c63c963\" 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>Upon extraction, you should see a different syntax in the base translation file (POT):<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">#: main_babel.py:21<\/span>\nmsgid <span class=\"hljs-string\">\"ans-age\"<\/span>\nmsgid_plural <span class=\"hljs-string\">\"ans-age-plural\"<\/span>\nmsgstr&#91;<span class=\"hljs-number\">0<\/span>] <span class=\"hljs-string\">\"\"<\/span>\nmsgstr&#91;<span class=\"hljs-number\">1<\/span>] <span class=\"hljs-string\">\"\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_d6afe068ded34c0a2aa7b189baca73b0\" 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 number of <code>msgstr<\/code> is based on the number of plural forms specified for the locale. Different locales have different amounts of plural forms: While English has 2 plural forms, Arabic has 6.<\/p>\n<p>A comment at the top of the file shows how a locale&#8217;s plural form for a message is resolved. For example:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-string\">\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><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_7d71b756faf25daf0fe1ec4df2ad1169\" 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> The pluralization syntax is based on the <a href=\"https:\/\/www.unicode.org\/reports\/tr35\/tr35-33\/tr35-numbers.html#Language_Plural_Rules\">CDLR rules<\/a>.<\/p>\n<p>Have a look at the following examples:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"># 2 plural forms\n\"Plural-Forms: nplurals=2; plural=(n != 1)\\n\"\n\n# 3 plural forms\n\"Plural-Forms: nplurals=3; plural=(n%10==1 <span class=\"hljs-symbol\">&amp;amp;<\/span><span class=\"hljs-symbol\">&amp;amp;<\/span> n%100!=11 ? 0 : n%10<span class=\"hljs-symbol\">&amp;gt;<\/span>=2 <span class=\"hljs-symbol\">&amp;amp;<\/span><span class=\"hljs-symbol\">&amp;amp;<\/span> \"\n\"n%10<span class=\"hljs-symbol\">&amp;lt;<\/span>=4 <span class=\"hljs-symbol\">&amp;amp;<\/span><span class=\"hljs-symbol\">&amp;amp;<\/span> (n%100<span class=\"hljs-symbol\">&amp;lt;<\/span>10 || n%100<span class=\"hljs-symbol\">&amp;gt;<\/span>=20) ? 1 : 2)\\n\"\n\n# 6 plural forms\n\"Plural-Forms: nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : \"\n\"n%100<span class=\"hljs-symbol\">&amp;gt;<\/span>=3 <span class=\"hljs-symbol\">&amp;amp;<\/span><span class=\"hljs-symbol\">&amp;amp;<\/span> n%100<span class=\"hljs-symbol\">&amp;lt;<\/span>=10 ? 3 : n%100<span class=\"hljs-symbol\">&amp;gt;<\/span>=0 <span class=\"hljs-symbol\">&amp;amp;<\/span><span class=\"hljs-symbol\">&amp;amp;<\/span> n%100<span class=\"hljs-symbol\">&amp;lt;<\/span>=2 ? 4 : 5)\\n\"<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><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_af9f2059d858ee4f0f8d641884216a3d\" 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>You can get the pluralized text as follows:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-29\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">import gettext\n\n<span class=\"hljs-comment\"># initialization<\/span>\nlang_en = gettext.translation(<span class=\"hljs-string\">'messages'<\/span>, localedir=<span class=\"hljs-string\">'data'<\/span>, languages=&#91;<span class=\"hljs-string\">'en'<\/span>])\n\n<span class=\"hljs-comment\"># set current locale to en<\/span>\nlang_en.install(names=&#91;<span class=\"hljs-string\">'gettext'<\/span>,\u00a0<span class=\"hljs-string\">'ngettext'<\/span>])\n\n<span class=\"hljs-keyword\">print<\/span>(ngettext(<span class=\"hljs-string\">'ans-age'<\/span>, <span class=\"hljs-string\">'ans-age-plural'<\/span>, age).format(count=<span class=\"hljs-number\">1<\/span>))\n<span class=\"hljs-comment\"># You are 1 year old<\/span>\n\n<span class=\"hljs-keyword\">print<\/span>(ngettext(<span class=\"hljs-string\">'ans-age'<\/span>, <span class=\"hljs-string\">'ans-age-plural'<\/span>, age).format(count=<span class=\"hljs-number\">12<\/span>))\n<span class=\"hljs-comment\"># You are 12 years old<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-29\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_d947752c3da8e78e905c14dc060780d3\" 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<h3><span class=\"ez-toc-section\" id=\"using-gettext-in-your-application\"><\/span>Using gettext in your application<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Instead of loading each locale one by one, you can load the translation files dynamically and store them in a <code>dict<\/code> object as follows:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-30\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">import gettext\n\ntranslations = {}\nsupported_langs = &#91;<span class=\"hljs-string\">'en'<\/span>, <span class=\"hljs-string\">'de'<\/span>]\n\n<span class=\"hljs-comment\"># load translation files dynamically<\/span>\n<span class=\"hljs-keyword\">for<\/span> lang in supported_langs:\n    translations&#91;lang] = gettext.translation(<span class=\"hljs-string\">'messages'<\/span>, localedir=<span class=\"hljs-string\">'data'<\/span>, languages=&#91;lang])<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-30\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_210e628b72d98998f0f1f660e837c326\" 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, simply set the desired locale and call either the <code>_<\/code> or <code>ngettext<\/code> functions to get the desired translation texts:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-31\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">import gettext\n\ntranslations = {}\nsupported_langs = &#91;<span class=\"hljs-string\">'en'<\/span>, <span class=\"hljs-string\">'de'<\/span>]\n\n<span class=\"hljs-comment\"># load translation files dynamically<\/span>\n<span class=\"hljs-keyword\">for<\/span> lang in supported_langs:\n    translations&#91;lang] = gettext.translation(<span class=\"hljs-string\">'messages'<\/span>, localedir=<span class=\"hljs-string\">'data'<\/span>, languages=&#91;lang])\n\n<span class=\"hljs-comment\"># set active locale to en<\/span>\ntranslations&#91;<span class=\"hljs-string\">'en'<\/span>].install(names=&#91;<span class=\"hljs-string\">'gettext'<\/span>, <span class=\"hljs-string\">'ngettext'<\/span>])\n\nname = <span class=\"hljs-string\">'John Doe'<\/span>\n<span class=\"hljs-keyword\">print<\/span>(_(<span class=\"hljs-string\">'ans-name'<\/span>).format(name=name))\n<span class=\"hljs-comment\"># Hello, John Doe! Welcome to Phrase<\/span>\n\n<span class=\"hljs-comment\"># change the active locale to de<\/span>\ntranslations&#91;<span class=\"hljs-string\">'de'<\/span>].install(names=&#91;<span class=\"hljs-string\">'gettext'<\/span>, <span class=\"hljs-string\">'ngettext'<\/span>])\n<span class=\"hljs-keyword\">print<\/span>(_(<span class=\"hljs-string\">'ans-name'<\/span>).format(name=name))\n<span class=\"hljs-comment\"># Hallo, John Doe! Willkommen bei Phrase<\/span>\n\nage = <span class=\"hljs-number\">30<\/span>\ntext = ngettext(<span class=\"hljs-string\">'ans-age'<\/span>, <span class=\"hljs-string\">'ans-age-plural'<\/span>, age)\n<span class=\"hljs-keyword\">print<\/span>(text)\n<span class=\"hljs-comment\"># Du bist 30 Jahre alt<\/span>\n\ntext = text.format(count=age)\n<span class=\"hljs-keyword\">print<\/span>(text)\n<span class=\"hljs-comment\"># Du bist 30 Jahre alt<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-31\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_399745608ef058117d403f32510ecfaf\" 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>Simply run the file as usual and you should get the same output as what we did previously using JSON or YAML.<\/p>\n<p>\ud83e\udd3f <em>Go deeper \u00bb<\/em> Check out our guide to <a href=\"https:\/\/phrase.com\/blog\/posts\/translate-python-gnu-gettext\/\">translating Python applications with the GNU gettext module<\/a> to learn more about the <code>gettext<\/code> module.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"how-can-a-python-app-support-right-to-left-languages\"><\/span>How can a Python app support right-to-left languages?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Python does not come with an out-of-the-box implementation for displaying text meant for right-to-left languages, but you can utilize the <code>python-bidi<\/code> module for such use cases. <code>python-bidi<\/code> is a Python implementation of a bi-directional (BiDi) layout. It provides a convenient function to display right-to-left languages. Run the following command to install it:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">pip install python-bidi<\/code><\/span><\/pre>\n\n\n<div id=\"acf\/text-block_9c30bd33ba741f4de7952222b90e772d\" 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 comes with the <code>get_display<\/code> function to display a string bi-directionally:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-32\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">from<\/span> bidi.algorithm <span class=\"hljs-keyword\">import<\/span> get_display\n\nget_display(<span class=\"hljs-string\">'\u0627\u064e\u0644\u0652\u0639\u064e\u0631\u064e\u0628\u0650\u064a\u064e\u0651\u0629\u064f'<\/span>)<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-32\"><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_aed00ffb09b27fc8453d05a6ed72d619\" 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>You should get the following output when you print the result:<\/p>\n<p style=\"text-align: right;\">\u0627\u064e\u0644\u0652\u0639\u064e\u0631\u064e\u0628\u0650\u064a\u064e\u0651\u0629\u064f<\/p>\n<h2><span class=\"ez-toc-section\" id=\"how-do-i-format-localized-dates-and-times-in-python\"><\/span>How do I format localized dates and times in Python?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Python has its own built-in <code>datetime<\/code> module for manipulating dates and times. It supports arithmetic operations on objects, making it extremely useful for localization and internationalization.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"how-do-i-work-with-date-and-time-duration\"><\/span>How do I work with date and time duration?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>A <code>timedelta<\/code> object represents the difference between 2 dates or times. You can think of it as a duration. It accepts the following input arguments:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">datetime.timedelta(milliseconds=0, microseconds=0, seconds=0, minutes=0, hours=0, days=0, weeks=0)<\/code><\/span><\/pre>\n\n\n<div id=\"acf\/text-block_e039fc9630d7aff1f2e11ce4b09c2925\" 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>You can create a new <code>timedelta<\/code> as follows:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-33\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">from datetime import timedelta\n\ndelta = timedelta(\n    seconds=<span class=\"hljs-number\">27<\/span>,\n    minutes=<span class=\"hljs-number\">5<\/span>,\n    hours=<span class=\"hljs-number\">8<\/span>,\n    days=<span class=\"hljs-number\">50<\/span>,\n    weeks=<span class=\"hljs-number\">2<\/span>\n)\n\n<span class=\"hljs-comment\"># 64 days, 8:05:27<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-33\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_698655f5a025e65879fe20de3d194081\" 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>\ud83e\udd3f <em>Go deeper \u00bb<\/em> Check out the <a href=\"https:\/\/docs.python.org\/3\/library\/datetime.html#timedelta-objects\">Timedelta objects<\/a>\u00a0documentation to learn more about the <code>Timedelta<\/code> class.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"how-can-i-use-datetimes\"><\/span>How can I use datetimes?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>A <code>time<\/code> object represents a local time of the day regardless of the date, while a <code>date<\/code> represents a date in a calendar. Often the ideal choice is to use the <code>datetime<\/code> object. It contains all the relevant information related to time and date. The <code>datetime<\/code> object can be categorized as <code>naive<\/code> or <code>aware<\/code>, depending on whether it contains information related to timezone.<\/p>\n<p>\ud83e\udd3f <em>Go deeper \u00bb<\/em> Check out the <a href=\"https:\/\/docs.python.org\/3\/library\/datetime.html#aware-and-naive-objects\">Aware and Naive Objects<\/a>\u00a0documentation to learn more about them.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-34\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">from datetime import datetime, timedelta, timezone\n\n<span class=\"hljs-comment\"># naive datetime obj<\/span>\ndt = datetime.now()\n<span class=\"hljs-comment\"># 2022-06-12 15:48:40.014838<\/span>\n\n<span class=\"hljs-comment\"># aware datetime obj (GMT+8)<\/span>\ntz = timezone(timedelta(hours=<span class=\"hljs-number\">8<\/span>))\ndt = datetime.now(tz=tz)\n<span class=\"hljs-comment\"># 2022-06-12 15:48:40.014838+08:00<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-34\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_267dbe1fb6c3d92e75fc3a47bc191aa0\" 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>A <code>datetime<\/code> object supports the following methods for datetime conversion:<\/p>\n<ul>\n<li><code>strftime<\/code>: convert a <code>datetime<\/code> object to a string according to a given format<\/li>\n<li><code>strptime<\/code>: parse a string into a <code>datetime<\/code> object given a corresponding format<\/li>\n<\/ul>\n<p>The <code>strftime<\/code> function accepts a string, which indicates the corresponding date and time format. This comes in handy when localizing the content of an application.<\/p>\n<p>\ud83e\udd3f <em>Go deeper \u00bb<\/em> Check out the <a href=\"https:\/\/docs.python.org\/3\/library\/datetime.html#strftime-and-strptime-behavior\">strftime and strptime<\/a>\u00a0documentation to learn more about them.<\/p>\n<p>Have a look at the following code snippet which displays different string output depending on the input format string.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-35\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">from datetime import datetime, timezone\n\ndt = datetime(year=<span class=\"hljs-number\">2022<\/span>, month=<span class=\"hljs-number\">6<\/span>, day=<span class=\"hljs-number\">12<\/span>, hour=<span class=\"hljs-number\">16<\/span>, minute=<span class=\"hljs-number\">32<\/span>, second=<span class=\"hljs-number\">45<\/span>, tzinfo=timezone.utc)\n\ndt.strftime(<span class=\"hljs-string\">'%Y-%m-%d %H:%M:%S'<\/span>)\n<span class=\"hljs-comment\"># 2022-06-12 16:32:45<\/span>\n\ndt.strftime(<span class=\"hljs-string\">'%b %d, %Y'<\/span>)\n<span class=\"hljs-comment\"># Jun 12, 2022<\/span>\n\ndt.strftime(<span class=\"hljs-string\">'%A (%I.%M %p)'<\/span>)\n<span class=\"hljs-comment\"># Sunday (04.32 PM)<\/span>\n\ndt.strftime(<span class=\"hljs-string\">'%c'<\/span>)\n<span class=\"hljs-comment\"># Sun Jun 12 16:32:45 2022<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-35\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_00c8bcaa83c5447b79fc4924301dcc4a\" 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 format depends on the existing locale of the application. You can use the built-in <code>locale<\/code> module to change it.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-36\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">import locale\n\n<span class=\"hljs-comment\"># get current locale<\/span>\nlocale.getlocale()\n<span class=\"hljs-comment\"># ('English_Singapore', '1252')<\/span>\n\nlocale.setlocale(locale.LC_ALL, <span class=\"hljs-string\">'de_DE'<\/span>)\n<span class=\"hljs-comment\"># ('de_DE', 'ISO8859-1')<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-36\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_09622bcf594cb2dd57487da98ac88e52\" 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>\ud83e\udd3f <em>Go deeper \u00bb<\/em> Check out our <a href=\"https:\/\/phrase.com\/blog\/posts\/beginners-guide-to-locale-in-python\/\">beginner\u2019s guide to Python\u2019s locale module<\/a>\u00a0to learn more about the <code>locale<\/code> module.<\/p>\n<p>Let\u2019s test it again using <code>de_DE<\/code> (German in Germany) as the current locale instead:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-37\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">from datetime import datetime, timezone\nimport locale\n\nlocale.setlocale(locale.LC_ALL, <span class=\"hljs-string\">'de_DE'<\/span>)\n\ndt = datetime(year=<span class=\"hljs-number\">2022<\/span>, month=<span class=\"hljs-number\">6<\/span>, day=<span class=\"hljs-number\">12<\/span>, hour=<span class=\"hljs-number\">16<\/span>, minute=<span class=\"hljs-number\">32<\/span>, second=<span class=\"hljs-number\">45<\/span>, tzinfo=timezone.utc)\n\ndt.strftime(<span class=\"hljs-string\">'%Y-%m-%d %H:%M:%S'<\/span>)\n<span class=\"hljs-comment\"># 2022-06-12 16:32:45<\/span>\n\ndt.strftime(<span class=\"hljs-string\">'%b %d, %Y'<\/span>)\n<span class=\"hljs-comment\"># Jun 12, 2022<\/span>\n\ndt.strftime(<span class=\"hljs-string\">'%A (%I.%M %p)'<\/span>)\n<span class=\"hljs-comment\"># Sonntag (04.32 )<\/span>\n\ndt.strftime(<span class=\"hljs-string\">'%c'<\/span>)\n<span class=\"hljs-comment\"># 12.06.2022 16:32:45<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-37\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_3aa71eb8060046c33dadc69b04da908c\" 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>On the other hand, the <code>strptime<\/code> function takes in 2 input arguments:<\/p>\n<ul>\n<li><code>date_string<\/code>: a string representation of a datetime based on <a href=\"https:\/\/docs.python.org\/3\/library\/datetime.html#strftime-and-strptime-format-codes\">1989 C standard<\/a>.<\/li>\n<li><code>format<\/code>: the format to parse the input <code>date_string<\/code><\/li>\n<\/ul>\n<p>\ud83d\uddd2 <em>Note \u00bb<\/em> The <code>strptime<\/code> function cares about the current locale when parsing the input.<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-38\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">from datetime import datetime\n\ntext = <span class=\"hljs-string\">'2022-06-12 16:32:45'<\/span>\nformat = <span class=\"hljs-string\">'%Y-%m-%d %H:%M:%S'<\/span>\n\ndatetime.strptime(text, format)\n<span class=\"hljs-comment\"># 2022-06-12 16:32:45<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-38\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_01688e38439c572128bc94f9706fe871\" 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<h3><span class=\"ez-toc-section\" id=\"how-do-i-format-localized-dates-with-babel\"><\/span>How do I format localized dates with Babel?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Alternatively, you can utilize the <code>babel.dates<\/code> module to format date and time.<\/p>\n<h4>A note on Babel<\/h4>\n<p>The <code>babel<\/code> module is a collection of utilities for l10n and i18n in Python. It is actively maintained and offers the following features:<\/p>\n<ul>\n<li>Datetime formatting<\/li>\n<li>Number formatting<\/li>\n<li>Currency formatting<\/li>\n<li>Generating message catalogs (translation files)<\/li>\n<\/ul>\n<p>\ud83e\udd3f <em>Go deeper \u00bb<\/em> Check out <a href=\"https:\/\/phrase.com\/blog\/posts\/i18n-advantages-babel-python\/\">Babel\u2019s i18n advantages for multilingual apps<\/a>\u00a0to learn more about the <code>babel<\/code> module.<\/p>\n<p>OK, back to date formatting. <code>babel.dates<\/code> comes with the following functions:<\/p>\n<ul>\n<li>format_time<\/li>\n<li>format_date<\/li>\n<li>format_datetime<\/li>\n<\/ul>\n<p>Have a look at the following code snippet for the usage of Babel&#8217;s formatting functions:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-39\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">from datetime import datetime, timezone\nfrom babel.dates import format_time, format_date, format_datetime\n\ndt = datetime(year=<span class=\"hljs-number\">2022<\/span>, month=<span class=\"hljs-number\">6<\/span>, day=<span class=\"hljs-number\">12<\/span>, hour=<span class=\"hljs-number\">16<\/span>, minute=<span class=\"hljs-number\">32<\/span>, second=<span class=\"hljs-number\">45<\/span>, tzinfo=timezone.utc)\n\n<span class=\"hljs-comment\"># using the default medium format<\/span>\nformat_time(dt, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># 4:32:45 PM<\/span>\n\nformat_date(dt, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># Jun 12, 2022<\/span>\n\nformat_datetime(dt, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># Jun 12, 2022, 4:32:45 PM<\/span>\n\n<span class=\"hljs-comment\"># using full format<\/span>\nformat_time(dt, format=<span class=\"hljs-string\">'full'<\/span>, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># 4:32:45 PM Coordinated Universal Time<\/span>\n\nformat_date(dt, format=<span class=\"hljs-string\">'full'<\/span>, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># Sunday, June 12, 2022<\/span>\n\nformat_datetime(dt, format=<span class=\"hljs-string\">'full'<\/span>, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># Sunday, June 12, 2022 at 4:32:45 PM Coordinated Universal Time<\/span>\n\n<span class=\"hljs-comment\"># using German locale<\/span>\nformat_time(dt, format=<span class=\"hljs-string\">'full'<\/span>, locale=<span class=\"hljs-string\">'de_DE'<\/span>)\n<span class=\"hljs-comment\"># 16:32:45 Koordinierte Weltzeit<\/span>\n\nformat_date(dt, format=<span class=\"hljs-string\">'full'<\/span>, locale=<span class=\"hljs-string\">'de_DE'<\/span>)\n<span class=\"hljs-comment\"># Sonntag, 12. Juni 2022<\/span>\n\nformat_datetime(dt, format=<span class=\"hljs-string\">'full'<\/span>, locale=<span class=\"hljs-string\">'de_DE'<\/span>)\n<span class=\"hljs-comment\"># Sonntag, 12. Juni 2022 um 16:32:45 Koordinierte Weltzeit<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-39\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_1c473b6648530ff02ab1308104f7c4ff\" 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 <code>format<\/code> argument is optional and can be one of the following choices:<\/p>\n<ul>\n<li>Short<\/li>\n<li>Medium (the default value)<\/li>\n<li>Long<\/li>\n<li>Full<\/li>\n<\/ul>\n<p>\ud83d\uddd2 <em>Note \u00bb<\/em> The final output is based on the input <code>locale<\/code> argument.<\/p>\n<p>\ud83e\udd3f <em>Go deeper \u00bb<\/em> Check out the <a href=\"https:\/\/babel.pocoo.org\/en\/latest\/dates.html#date-fields\">babel.dates fields<\/a> documentation to learn more about custom patterns.<\/p>\n<h4>How do I use babel to work with time zones?<\/h4>\n<p>You can utilize the <code>get_timezone<\/code> function to create a new timezone object based on timezone names such as <code>US\/Eastern<\/code> or <code>Europe\/Berlin<\/code>. Then, pass the object as input for <code>tzinfo<\/code> argument:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-40\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">from datetime import datetime, timezone\nfrom babel.dates import get_timezone, format_datetime\n\ndt = datetime(year=<span class=\"hljs-number\">2022<\/span>, month=<span class=\"hljs-number\">6<\/span>, day=<span class=\"hljs-number\">12<\/span>, hour=<span class=\"hljs-number\">16<\/span>, minute=<span class=\"hljs-number\">32<\/span>, second=<span class=\"hljs-number\">45<\/span>, tzinfo=timezone.utc)\n\neastern = get_timezone(<span class=\"hljs-string\">'US\/Eastern'<\/span>)\nberlin = get_timezone(<span class=\"hljs-string\">'Europe\/Berlin'<\/span>)\n\n<span class=\"hljs-comment\"># using eastern timezone<\/span>\nformat_datetime(dt, format=<span class=\"hljs-string\">'full'<\/span>, locale=<span class=\"hljs-string\">'en_US'<\/span>, tzinfo=eastern)\n<span class=\"hljs-comment\"># Sunday, June 12, 2022 at 12:32:45 PM Eastern Daylight Time<\/span>\n\n<span class=\"hljs-comment\"># using berlin timezone<\/span>\nformat_datetime(dt, format=format, locale=<span class=\"hljs-string\">'en_US'<\/span>, tzinfo=berlin)\n<span class=\"hljs-comment\"># Sunday, June 12, 2022 at 6:32:45 PM Central European Summer Time<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-40\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_deea0f2fefed5d16201d6d7fe41b1e90\" 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=\"how-do-i-format-localized-numbers-in-python\"><\/span>How do I format localized numbers in Python?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Number formatting can be tricky when it comes to internationalization. For example, the text <code>12,345<\/code> conveys different meanings for English US (<code>en_US<\/code>) and German (<code>de_DE<\/code>). This is mainly because different languages use different symbols for decimal points and thousand separators.<\/p>\n<p>\ud83e\udd3f <em>Go deeper \u00bb <\/em>Our concise guide to <a href=\"https:\/\/phrase.com\/blog\/posts\/number-localization\/\">number localization<\/a> covers grouping, separators, numeral systems, and more.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"how-do-i-use-the-built-in-locale-module-to-format-numbers\"><\/span>How do I use the built-in locale module to format numbers?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>For conversion from string to integer or floating point, the <code>locale<\/code> module is a good option. It comes with the following built-in function:<\/p>\n<ul>\n<li><code>atoi<\/code>: convert a string to an integer using the current locale numeric conventions<\/li>\n<li><code>atof<\/code>: convert a string to a floating point using the current locale numeric conventions<\/li>\n<\/ul>\n<p>Given <code>12,345<\/code> as the input string, the results of <code>atof<\/code> for both languages are as follows:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-41\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">import locale\n\n<span class=\"hljs-comment\"># English<\/span>\nlocale.setlocale(locale.LC_ALL, <span class=\"hljs-string\">'en_US'<\/span>)\nlocale.atof(<span class=\"hljs-string\">'12,345'<\/span>)\n<span class=\"hljs-comment\"># 12345.0<\/span>\n\n<span class=\"hljs-comment\"># German<\/span>\nlocale.setlocale(locale.LC_ALL, <span class=\"hljs-string\">'de_DE'<\/span>)\nlocale.atof(<span class=\"hljs-string\">'12,345'<\/span>)\n<span class=\"hljs-comment\"># 12.345<\/span>\n\n<span class=\"hljs-comment\"># English<\/span>\nlocale.setlocale(locale.LC_ALL, <span class=\"hljs-string\">'en_US'<\/span>)\nlocale.atof(<span class=\"hljs-string\">'12.345'<\/span>)\n<span class=\"hljs-comment\"># 12.345<\/span>\n\n<span class=\"hljs-comment\"># German<\/span>\nlocale.setlocale(locale.LC_ALL, <span class=\"hljs-string\">'de_DE'<\/span>)\nlocale.atof(<span class=\"hljs-string\">'12.345'<\/span>)\n<span class=\"hljs-comment\"># 12345.0<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-41\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_4b2a4adb5e65dd14562c177919da20cd\" 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>On the other hand, you can utilize the <code>format_string<\/code> function to convert a number into a localized string. It accepts the following input argument:<\/p>\n<ul>\n<li><code>format<\/code>: a string representing the <a href=\"https:\/\/docs.python.org\/3\/library\/string.html#format-specification-mini-language\">format specification<\/a><\/li>\n<li><code>val<\/code>: a number<\/li>\n<li><code>grouping<\/code>: whether to take grouping into account. Grouping refers to a sequence of numbers specifying which relative positions the thousand separator is expected. It is <code>False<\/code> by default.<\/li>\n<\/ul>\n<p>Have a look at the following code snippet:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-42\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">import locale\n\nlocale.setlocale(locale.LC_ALL, <span class=\"hljs-string\">'en_US'<\/span>)\nlocale.format_string(<span class=\"hljs-string\">'%10.2f'<\/span>, <span class=\"hljs-number\">123456.78<\/span>)\n<span class=\"hljs-comment\"># 123456.78<\/span>\n\nlocale.format_string(<span class=\"hljs-string\">'%10.2f'<\/span>, <span class=\"hljs-number\">123456.78<\/span>, grouping=<span class=\"hljs-keyword\">True<\/span>)\n<span class=\"hljs-comment\"># 123,456.78<\/span>\n\nlocale.setlocale(locale.LC_ALL, <span class=\"hljs-string\">'de_DE'<\/span>)\nlocale.format_string(<span class=\"hljs-string\">'%10.2f'<\/span>, <span class=\"hljs-number\">123456.78<\/span>)\n<span class=\"hljs-comment\"># 123456,78<\/span>\n\nlocale.format_string(<span class=\"hljs-string\">'%10.2f'<\/span>, <span class=\"hljs-number\">123456.78<\/span>, grouping=<span class=\"hljs-keyword\">True<\/span>)\n<span class=\"hljs-comment\"># 123.456,78<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-42\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_65035831c65a57ca2c5385208260aa57\" 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<h3><span class=\"ez-toc-section\" id=\"how-do-i-use-babel-to-format-localized-numbers\"><\/span>How do I use babel to format localized numbers?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Alternatively, you can utilize the following locale-specific formatting functions provided by the <code>babel.numbers<\/code> module:<\/p>\n<ul>\n<li><code>format_decimal<\/code>: format a given number based on the input locale<\/li>\n<li><code>format_percent<\/code>: format a given number to percentage based on the input locale<\/li>\n<li><code>format_scientific<\/code>: format a given number to scientific notation based on the input locale. It uses <code>E<\/code> as the notation for power of 10<\/li>\n<\/ul>\n<p>The following code snippet illustrates the output for <code>format_decimal<\/code> when using different locales:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-43\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">from babel.numbers import format_decimal, format_percent, format_scientific\n\nformat_decimal(<span class=\"hljs-number\">12345<\/span>, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># 12,345<\/span>\nformat_decimal(<span class=\"hljs-number\">12345.67<\/span>, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># 12,345.67<\/span>\nformat_decimal(<span class=\"hljs-number\">12345<\/span>, locale=<span class=\"hljs-string\">'de_DE'<\/span>)\n<span class=\"hljs-comment\"># 12.345<\/span>\nformat_decimal(<span class=\"hljs-number\">12345.67<\/span>, locale=<span class=\"hljs-string\">'de_DE'<\/span>)\n<span class=\"hljs-comment\"># 12.345,67<\/span>\n\nformat_percent(<span class=\"hljs-number\">0.34<\/span>, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># 34%<\/span>\nformat_percent(<span class=\"hljs-number\">0.34<\/span>, locale=<span class=\"hljs-string\">'de_DE'<\/span>)\n<span class=\"hljs-comment\"># 34 %<\/span>\n\nformat_scientific(<span class=\"hljs-number\">1234567<\/span>, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># 1.234567E6<\/span>\nformat_scientific(<span class=\"hljs-number\">1234567<\/span>, locale=<span class=\"hljs-string\">'de_DE'<\/span>)\n<span class=\"hljs-comment\"># 1,234567E6<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-43\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_902e1d2a015d5c68b8f53cec94369705\" 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\uddd2 <em>Note \u00bb<\/em> Unlike the <code>locale.format_string<\/code> function, the <code>babel.numbers.format_decimal<\/code> function allows parsing of custom patterns.<\/p>\n<p>\ud83e\udd3f <em>Go deeper \u00bb<\/em> Check out the <a href=\"https:\/\/babel.pocoo.org\/en\/latest\/numbers.html#pattern-syntax\">Custom Pattern Syntax<\/a> documentation to learn more about custom patterns.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"how-do-i-format-localized-currency-in-python\"><\/span>How do I format localized currency in Python?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Currency formatting takes into account the currency symbol and locale. For example, the symbols <code>\u20ac<\/code> and <code>EUR<\/code> represent euros and can be used interchangeably.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"how-do-i-use-the-built-in-locale-module-to-format-currency\"><\/span>How do I use the built-in locale module to format currency?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>The built-in <code>locale<\/code> module comes with the <code>currency<\/code> function to format currency. There is an optional <code>international<\/code> argument to display the currency using the international name instead of the currency symbol.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"how-do-i-use-babel-to-format-localized-currency\"><\/span>How do I use Babel to format localized currency?<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>The <code>babel.numbers<\/code> module comes with the <code>format_currency<\/code> function that considers both the locale and currency. It means that you can format a number using <code>de_DE<\/code> locale for <code>USD<\/code>.<\/p>\n<p>Have a look at the following code snippet to understand more:<\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-44\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">import locale\nfrom\u00a0babel.numbers\u00a0import\u00a0format_currency\n\nlocale.setlocale(locale.LC_ALL, <span class=\"hljs-string\">'en_US'<\/span>)\nlocale.currency(<span class=\"hljs-number\">1234.56<\/span>)\n<span class=\"hljs-comment\"># $1234.56<\/span>\nlocale.currency(<span class=\"hljs-number\">1234.56<\/span>, international=<span class=\"hljs-keyword\">True<\/span>)\n<span class=\"hljs-comment\"># USD1234.56<\/span>\n\nformat_currency(<span class=\"hljs-number\">1234.56<\/span>, <span class=\"hljs-string\">'USD'<\/span>, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># $1,234.56<\/span>\n<span class=\"hljs-comment\"># set the currency to EURO<\/span>\nformat_currency(<span class=\"hljs-number\">1234.56<\/span>, <span class=\"hljs-string\">'EUR'<\/span>, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># \u20ac1,234.56<\/span>\n<span class=\"hljs-comment\"># set the currency to Japan YEN<\/span>\nformat_currency(<span class=\"hljs-number\">1234.56<\/span>, <span class=\"hljs-string\">'JYP'<\/span>, locale=<span class=\"hljs-string\">'en_US'<\/span>)\n<span class=\"hljs-comment\"># JYP1,234.56<\/span>\n\n\n\nlocale.setlocale(locale.LC_ALL, <span class=\"hljs-string\">'de_DE'<\/span>)\nlocale.currency(<span class=\"hljs-number\">1234.56<\/span>)\n<span class=\"hljs-comment\"># 1234,56 \u20ac<\/span>\nlocale.currency(<span class=\"hljs-number\">1234.56<\/span>, international=<span class=\"hljs-keyword\">True<\/span>)\n<span class=\"hljs-comment\"># 1234,56 EUR<\/span>\n\nformat_currency(<span class=\"hljs-number\">1234.56<\/span>, <span class=\"hljs-string\">'USD'<\/span>, locale=<span class=\"hljs-string\">'de_DE'<\/span>)\n<span class=\"hljs-comment\"># 1.234,56 $<\/span>\nformat_currency(<span class=\"hljs-number\">1234.56<\/span>, <span class=\"hljs-string\">'EUR'<\/span>, locale=<span class=\"hljs-string\">'de_DE'<\/span>)\n<span class=\"hljs-comment\"># 1.234,56 \u20ac<\/span>\nformat_currency(<span class=\"hljs-number\">1234.56<\/span>, <span class=\"hljs-string\">'JYP'<\/span>, locale=<span class=\"hljs-string\">'de_DE'<\/span>)\n<span class=\"hljs-comment\"># 1.234,56 JYP<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-44\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_576f2475675aa20c842580219f3b0f8a\" 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\uddd2 <em>Note \u00bb<\/em> Unlike the <code>locale.format_currency<\/code> function, the <code>babel.numbers.format_currency<\/code> function allows you to specify the currency explicitly. Instead of having USD bound to <code>en_US<\/code> locale, you can display the desired currency via the <code>currency<\/code> argument.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"wrapping-up\"><\/span>Wrapping up<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>We are done! By now, you should have all the knowledge required to localize and internationalize Python applications.\u00a0 If you are building web applications in Python and looking for built-in localization methods, consider checking out the following articles:<\/p>\n<ul>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/falcon-python-i18n\/\">An I18n Walkthrough for Falcon Web Apps in Python<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/tornado-web-framework-i18n\/\">A Step-by-Step Tutorial on Python Tornado<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/cherrypy-i18n\/\">CherryPy I18n Cookbook with Babel and Jinja2<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/pyramid-i18n-tutorial\/\">Pyramid I18n Tutorial From Scratch<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/flask-app-tutorial-i18n\/\">Flask App Tutorial on Internationalization<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/website-i18n-with-django-rest-framework-and-django-parler\/\">Website I18n with Django REST Framework and django-parler<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/quick-guide-django-i18n\/\">A Quick Guide to Django i18n<\/a><\/li>\n<\/ul>\n<p>If you want to further streamline your localization process, consider signing up for Phrase, the most connective and customiziable suite of translation automation technology available.<\/p>\n<p>Phrase comes with a <a href=\"https:\/\/eu.phrase.com\/idm-ui\/signup\">14-day free trial<\/a> and can provide you with everything you need to:<\/p>\n<ul>\n<li>Build production-ready integrations with your development workflow<\/li>\n<li>Invite as many users as you wish to collaborate on your projects<\/li>\n<li>Edit and convert localization files online with more context for higher translation quality.<\/li>\n<\/ul>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Follow our step-by-step guide to preparing Python apps for localization and get to know common modules that can help you implement multilingual support for a global user base.<\/p>\n","protected":false},"author":61,"featured_media":38665,"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-38624","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\/38624"}],"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=38624"}],"version-history":[{"count":50,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/38624\/revisions"}],"predecessor-version":[{"id":83802,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/38624\/revisions\/83802"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/media\/38665"}],"wp:attachment":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/media?parent=38624"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/categories?post=38624"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}