<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Julia Herasymchuk</title>
    <description>The latest articles on DEV Community by Julia Herasymchuk (@juliaherasymchuk).</description>
    <link>https://dev.to/juliaherasymchuk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F871043%2Fe624158f-3baa-4976-b1cf-965133a1f364.jpeg</url>
      <title>DEV Community: Julia Herasymchuk</title>
      <link>https://dev.to/juliaherasymchuk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/juliaherasymchuk"/>
    <language>en</language>
    <item>
      <title>How to Localize your SaaS Application: Best Practices</title>
      <dc:creator>Julia Herasymchuk</dc:creator>
      <pubDate>Tue, 27 Dec 2022 16:51:44 +0000</pubDate>
      <link>https://dev.to/juliaherasymchuk/how-to-localize-your-saas-application-best-practices-400n</link>
      <guid>https://dev.to/juliaherasymchuk/how-to-localize-your-saas-application-best-practices-400n</guid>
      <description>&lt;p&gt;As a SaaS business grows, it becomes more important for you to make your product available to users all over the world. As more and more customers from different locales come in, you might start to wonder how to tackle SaaS localization and translation without creating extra work or complicating the processes that already work.&lt;/p&gt;

&lt;p&gt;No matter how much content you have and how many people are creating and editing it, with the proper infrastructure and tools, it is possible to create a multilingual product that will help you win customers speaking different languages and grow your business. Translation and localization can be automated, so there’s no copy-pasting for you.&lt;/p&gt;

&lt;p&gt;This article will cover all you need to know about localizing SaaS applications and how to do it with Crowdin.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is SaaS?
&lt;/h2&gt;

&lt;p&gt;Simply put, SaaS products can be accessed via the Internet instead of being installed on your machine. This makes software much more accessible to a broader range of users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Should You Localize Your SAAS Application?
&lt;/h2&gt;

&lt;p&gt;Software as a service (SaaS), also called on-demand software or cloud-based software, has become very popular and is used by many big and small businesses. Most SaaS companies use English as a primary language for their products. Since not all customers speak English as their first language, they want to use SaaS apps in the language they prefer. This is what drives the discussion about localization.&lt;/p&gt;

&lt;p&gt;Let’s talk about how localizing SaaS can help your company.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remove language barriers to improve user activation
&lt;/h2&gt;

&lt;p&gt;Language, and cultural barriers can make it hard for your SaaS product to reach users in other countries with the same success as solutions available in the local language.&lt;/p&gt;

&lt;p&gt;Localization lets you communicate better with your customers and stay close to them. The first steps in introducing users to your product are a localized website and user interface. To improve the onboarding process, you can localize the onboarding messages and emails to guide customers through your product in their language.&lt;/p&gt;

&lt;p&gt;Build trust and better relationships with customers to reduce churn&lt;br&gt;
When done right, localization is a great way to win the trust of local customers and get more people to use your product or service in local markets.&lt;/p&gt;

&lt;p&gt;If people are already using your product, it’s your task to keep them happy. At this point, you can provide support in their native language. This includes help articles and blog translations. You can also create multilingual chatbots or implement live chat translation. This way, your current customers will feel cared for, and you’ll be able to build a stronger relationship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stand out from your competition: gain a competitive edge
&lt;/h2&gt;

&lt;p&gt;Typically, when choosing a product, people test several solutions. They start a free trial, watch demos, and review your website content. Make your product stand out by making it available in your customers’ language. Soon, providing a product in several languages might not be an advantage, but it will be something users will expect by default, so start preparing now.&lt;/p&gt;

&lt;p&gt;Localizing for local languages also gives companies a competitive edge because you can communicate with locals better and get them to use your product even if they don’t speak the source language of your product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spend less (and boost your revenue)
&lt;/h2&gt;

&lt;p&gt;If you localize your SaaS product, you can make much more money. The more markets you go into, the higher your profit margins can get.&lt;/p&gt;

&lt;p&gt;But you can only get all of these benefits if you use the best SaaS localization practices. We’ll discuss this later in the article, but let’s look at one example.&lt;/p&gt;

&lt;p&gt;Such a simple thing as reviewing content before localization, or even better, writing content with localization in mind, can save you a lot of money. This way, you can ensure you’re not translating duplicate content or confusing translators with typos in the source text.&lt;/p&gt;

&lt;p&gt;Writing for international markets has its own rules. Writing in plain, straightforward language is better in an active voice. This way, it’s clear for translators how to convey your message. If you avoid ambiguity, it will take you less time to separate pieces of content, which will speed up the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Consider before You Start Localization
&lt;/h2&gt;

&lt;p&gt;Once you decide it’s time to reach new markets and improve conversions in the ones where you’re already present, you should create a plan for your localization initiative. As it might be tempting to localize into as many languages as possible immediately, we recommend setting your priorities before diving into this adventure.&lt;/p&gt;

&lt;p&gt;Here’s a list of things to consider before you start your localization project:&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose the markets you want to target
&lt;/h2&gt;

&lt;p&gt;There are at least two ways to start:&lt;/p&gt;

&lt;p&gt;You can enter entirely new markets where you have no customers yet. This would definitely take more time and effort, but results in the form of revenue can also be great.&lt;/p&gt;

&lt;p&gt;Or you can see where your product is already present, but the conversion rates are not what you want. This way, you already have some data to which you can compare your results.&lt;/p&gt;

&lt;p&gt;You need to choose specific locales and translate the text carefully. For example, if you have a big market in China or Japan, it makes sense to put Chinese and Japanese translations at the top of your list.&lt;/p&gt;

&lt;p&gt;Here are some strategies you can consider for choosing target languages:&lt;/p&gt;

&lt;p&gt;Leverage Google Analytics data. You can check which languages are the most common among your website visitors and bring you the most traffic. &lt;br&gt;
If you’re using universal Google Analytics, go to Audience &amp;gt; Geo &amp;gt; Language. You can also filter by Bounce rate using the same report to see for which languages it’s the highest, so you know these people leave your website and don’t see their language on it.&lt;/p&gt;

&lt;p&gt;You can run a survey in the UI or on your social media, asking your users which language they expect the most. It might not be the most accurate way, but it’s definitely a quick way to get answers.&lt;/p&gt;

&lt;p&gt;Market research. If your analytics team has already decided which markets you’re targeting - what is left is to choose the most common languages there and start your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing what to translate
&lt;/h2&gt;

&lt;p&gt;First, you must decide what and how you want to translate. Text is still the best option, but you could also localize pictures or videos. This would be a big plus because it would show that you have a unified approach to localization. It would be easier to update the translations if the service offered content made on the spot and pulled from an API.&lt;/p&gt;

&lt;p&gt;Make sure that as many translation strings as possible are taken care of. It wouldn’t make sense to have translations that aren’t quite right or are missing in many places, like buttons, labels, or modal messages. A translation management system can help keep track of messages that need to be translated.&lt;/p&gt;

&lt;p&gt;What type of content to localize in the SaaS product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Website&lt;/li&gt;
&lt;li&gt;Global SEO (Search Engine Optimization)&lt;/li&gt;
&lt;li&gt;Blog and help articles&lt;/li&gt;
&lt;li&gt;Email marketing campaigns&lt;/li&gt;
&lt;li&gt;Make adaptable design&lt;/li&gt;
&lt;li&gt;Text on pictures and video subtitles&lt;/li&gt;
&lt;li&gt;Chatbots and live chats.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read more in our previous article about how to make your product multilingual to increase your multilingual marketing strategy, and localize each type of content with the help of Crowdin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Organizing a translation team
&lt;/h2&gt;

&lt;p&gt;All parties involved in the localization process should be in sync with each other. For example, you need a localization manager who is in charge and has the final say on software requirements and technology decisions.&lt;/p&gt;

&lt;p&gt;You can invite translators and proofreaders you already work with to your organization or project. These could be&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In-house translators&lt;/li&gt;
&lt;li&gt;Freelancers&lt;/li&gt;
&lt;li&gt;Translators from the translation agencies you already work with&lt;/li&gt;
&lt;li&gt;Crowdin’s translation agency partners&lt;/li&gt;
&lt;li&gt;MT&lt;/li&gt;
&lt;li&gt;Communities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Crowdin Enterprise makes it easy to combine different approaches because each project has its workflow. Each workflow step can be given to a different person or vendor so they can work independently. Depending on the type of content or product you want to localize, you can use different methods to translate it.&lt;/p&gt;

&lt;p&gt;You don’t have time to hire someone to translate the content of your software. Crowdin Language Services lets you order translations with just a few clicks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Investing in software for localization
&lt;/h2&gt;

&lt;p&gt;Last but not least, another SaaS provider can help you with localization needs. This means you can buy specialized software to speed up the localization process and meet your needs as you go. For example, you might have only a few tasks in your plan. As your business grows, you may need to change your plan to include project management, integration with other systems, a translation memory, etc.&lt;/p&gt;

&lt;p&gt;Localization software enables businesses to centralize and automate their translation and localization workflows.&lt;/p&gt;

&lt;p&gt;In short, localization software includes things like&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A cloud-based shared workspace for all parties.&lt;/li&gt;
&lt;li&gt;Notifications for stakeholders about changes in the status of software localization.&lt;/li&gt;
&lt;li&gt;Support for all common file types.&lt;/li&gt;
&lt;li&gt;Software development kits or APIs are used to connect to the company’s existing systems.&lt;/li&gt;
&lt;li&gt;Software strings can be quickly and automatically imported from code repositories and exported when localization is done.&lt;/li&gt;
&lt;li&gt;Ability to look at translations of software before putting them online.&lt;/li&gt;
&lt;li&gt;Statistics about how well the software is localized.&lt;/li&gt;
&lt;li&gt;Keeping track of terms.&lt;/li&gt;
&lt;li&gt;Checks for quality assurance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;UI strings that need to be translated could have visual references.&lt;/p&gt;

&lt;p&gt;The ability to translate content by machine.&lt;br&gt;
On the surface, there seem to be a lot of different SaaS (software as a service) localization solutions on the market. However, not all localization software is created equal. Some are made with translators and their needs in mind, while others are made for developers or UX designers.&lt;/p&gt;

&lt;p&gt;But if you want great multilingual content, choose the universal all-in-one solution for localization, like Crowdin, which is easy for everyone on the team, including the product manager, developers, translators, decision-makers, and others. Also, make sure it meets your business goals and quality standards.&lt;/p&gt;

&lt;p&gt;Learn the key steps for the SaaS localization with the help of Crowdin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best Practices of SaaS localization with Crowdin
&lt;/h2&gt;

&lt;p&gt;Now that you have your list of priorities and are ready to start translating, you need to prepare. Here are the most critical steps to reaching that goal with the help of Crowdin:&lt;/p&gt;

&lt;h2&gt;
  
  
  Automate localization
&lt;/h2&gt;

&lt;p&gt;The best way to save time is through localization automation. A localization management platform like Crowdin helps you automate processes. Crowdin has over 450 apps and integrations that allow you to connect all of your tools to the content, send sources to Crowdin, and receive automatic translations back into your tools without copying and pasting. So, translators always have access to new content, and you get translations into the system, where you create content.&lt;/p&gt;

&lt;p&gt;Connect to the tools you already use&lt;br&gt;
Crowdin offers integrations with tools for localizing different content for your SaaS product, there are integrations in such categories as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CMS&lt;/li&gt;
&lt;li&gt;Marketing&lt;/li&gt;
&lt;li&gt;eCommerce&lt;/li&gt;
&lt;li&gt;Development&lt;/li&gt;
&lt;li&gt;Design&lt;/li&gt;
&lt;li&gt;File Management &amp;amp; Storage&lt;/li&gt;
&lt;li&gt;Customer Service&lt;/li&gt;
&lt;li&gt;Machine Translation&lt;/li&gt;
&lt;li&gt;TM &amp;amp; Glossaries&lt;/li&gt;
&lt;li&gt;File Formats&lt;/li&gt;
&lt;li&gt;Translator Productivity&lt;/li&gt;
&lt;li&gt;Manager Productivity&lt;/li&gt;
&lt;li&gt;Team Chat &amp;amp; Notifications&lt;/li&gt;
&lt;li&gt;Task Management&lt;/li&gt;
&lt;li&gt;Gaming&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you use Crowdin Apps to connect all the tools you need, you can set up continuous localization processes for any content you need to translate. Websites, blogs, onboarding materials, how-to articles, social media campaigns, and much more. SaaS localization might seem hard, but if you make a plan with the right tools and resources, it could help your business for a long time.&lt;/p&gt;

&lt;p&gt;Provide translators with productivity tools&lt;br&gt;
Translators can work on Crowdin in the Editor. The Editor gathers all the information the translation teams might need while working on the content. MT and TM engines’ suggestions, comments, search, filters, context, file preview, and terminology are all in one place. In addition to the usual features, you can add apps from the Store to the Crowdin Editor to make it more powerful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give more context for the better quality of the translation
&lt;/h2&gt;

&lt;p&gt;Whether you do the translation yourself or hire a team, the quality of the translation will depend on how good the team is. Still, even the best translators might get the sources wrong if they don’t have enough background information.&lt;/p&gt;

&lt;p&gt;When you set up a localization project, you shouldn’t skip the step of providing context. Crowdin gives you several ways to explain the context of a translation.&lt;br&gt;
In Crowdin, translators work in the Online Editor. Along with fields for the source and translated content, there is a field with the context added from the comments to each string in the codebase.&lt;/p&gt;

&lt;p&gt;Also, if any screenshots you uploaded had a string tag, the screenshot will be shown next to the source string. Find out more about how you can use screenshots to localize applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run QA checks to ensure your translations are correct
&lt;/h2&gt;

&lt;p&gt;Have a team of testers do both automated and manual localization testing to ensure everything is going well. Tell them to look for unusual situations when the text is too long, has memorable characters, finds the correct locale, and the images load correctly. Check to see if the text is shown slowly or if it flickers. You should also see if the currency and number formats suit the target region. For auditing, they need to report all the necessary test cases.&lt;/p&gt;

&lt;p&gt;One of the last steps in the translation process is usually proofreading. Once the translation is done, a proofreader can look over the text to find any mistakes and fix them. You can turn on Quality Assurance checks that help you make sure your translations are correct, precise, and free of mistakes to make things easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try automation of localization to speed up the process
&lt;/h2&gt;

&lt;p&gt;A lot of automation and continuous delivery are used in the SaaS model of agile application development. For your translation pipeline to be agile, you must add tasks and events that help you deliver the final product. Things like version control, git-ops, chat-ops, and webhooks can help you get ahead of the competition in a big way.&lt;/p&gt;

&lt;p&gt;Continuous localization makes sure that the localization process and the development process are both going at the same time. The localization software automatically finds new and changed strings and sends them when they are ready to be merged and published. It makes your localization workflow more efficient and gives you more options.&lt;/p&gt;

&lt;p&gt;Learn how continuous localization can benefit each team in our FREE e-book. It includes our own experience and thoughts about this approach for each department, as well as the thoughts of more than 10 experts in the localization field.&lt;/p&gt;

&lt;p&gt;If you want to find a good technology vendor to help you translate your SaaS content, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign up for Crowdin’s free trial to see how the platform works.&lt;/li&gt;
&lt;li&gt;Book a Demo with one of our experts and get answers to all your questions to make localization easier.&lt;/li&gt;
&lt;li&gt;Watch a recorded on-demand demo whenever you want to learn about the platform’s main features.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping It Up
&lt;/h2&gt;

&lt;p&gt;Since SaaS companies work well across borders, anyone on the planet should be able to get in touch with your company. The main difference between companies that offer localization and those that don’t is that the latter don’t have a strategic plan for making their user base accessible to everyone. This happens more often with essential services, where the choice of words depends on the area. By giving your users content that is more relevant to their needs, you give your SaaS platform a significant advantage over the competition and make it more credible.&lt;/p&gt;

</description>
      <category>watercooler</category>
    </item>
    <item>
      <title>Java i18n (Internationalization) and Localization Tutorial</title>
      <dc:creator>Julia Herasymchuk</dc:creator>
      <pubDate>Fri, 02 Sep 2022 08:46:04 +0000</pubDate>
      <link>https://dev.to/crowdin/java-i18n-internationalization-and-localization-tutorial-17bi</link>
      <guid>https://dev.to/crowdin/java-i18n-internationalization-and-localization-tutorial-17bi</guid>
      <description>&lt;p&gt;As an aspiring developer, finding a quick and reliable way to offer your app to the world can be challenging. It is the reason why you have to learn Java i18n and l10n (&lt;a href="https://blog.crowdin.com/2022/07/14/internationalization-vs-localization/"&gt;internationalization and localization&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Using Java, you already have the tools to detect the user’s locale and translate your app accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java Internationalization Is an Important Part of the Development
&lt;/h2&gt;

&lt;p&gt;Internationalization happens at the development stage, and the sooner it’s implemented – the fewer code changes would be required. However, there are some myths about i18n that we’d like to debunk:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Internalization is only about translating the text.&lt;/li&gt;
&lt;li&gt; It is challenging to implement it, and the process is burdensome. &lt;/li&gt;
&lt;li&gt; Only the project architect has to think about it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you might have guessed - these are all false statements. While localization is relatively simple to code even for a junior developer, many bundles and libraries provide ways to translate text from your app and make it culturally correct – this may include date formats, standards of measurement, or even the whole UI design.&lt;/p&gt;

&lt;p&gt;But is it demanding to create a new structure for your application? Nobody likes to go back to their code and rewrite everything repeatedly. An agile approach to software development teaches us to implement everything step-by-step, so the best case scenario is to build your project with internalization in mind.&lt;/p&gt;

&lt;p&gt;Let’s imagine the process like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  You create an application. &lt;/li&gt;
&lt;li&gt;  The app reads the user’s locale and formats, dates and numbers.&lt;/li&gt;
&lt;li&gt;  It then takes text data from the pre-defined resource and outputs the correct language to the user of our app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So there must be ways to store all your important messages in one place - you could translate them yourself or automate content updates using a convenient service such as Crowdin.&lt;/p&gt;

&lt;p&gt;With Crowdin, you can localize any git branches you want, or you can use CLI/API integrations. Read &lt;a href="https://blog.crowdin.com/2021/02/11/smart-ways-to-approach-mobile-app-localization/"&gt;more life hacks on app translation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Implement Internalization in Java
&lt;/h2&gt;

&lt;p&gt;Java is a powerful programming language that provides convenient ways to work with multi-lingual resources. The best way to do it is what’s called a ResourceBundle.&lt;/p&gt;

&lt;h3&gt;
  
  
  ResourceBundle Class
&lt;/h3&gt;

&lt;p&gt;ResourceBundle, together with Locale, are the fundamentals of internalization in Java. ResourceBundle class is used to read strings from text files (.properties).&lt;/p&gt;

&lt;p&gt;Imagine you could store all your Strings in one file, and the translators do the rest. That’s the job of the .properties file. Every single .properties file serves strings for each locale that your application supports.&lt;/p&gt;

&lt;p&gt;Properties usually have a standard naming:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ResouceBundleName&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;language_code&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;country_code&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for example, MessageBundle_uk_UA for new ResouceBundle&lt;/p&gt;

&lt;p&gt;MessageBundle.properties is the source language file&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ta-ezn9O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pf6fp7b911s1y7ubxf6j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ta-ezn9O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pf6fp7b911s1y7ubxf6j.png" alt="Image description" width="344" height="158"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the strings inside are organized like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addCity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Add&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chooseAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Choose&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeCity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Remove&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;tracker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changeLocale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Change&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;localization&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Exit&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;editCity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Edit&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;existing&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should organize all the strings into categories and be clear with their names. When we want to get the string - on the right - in our Java app, we call it using its name - on the left.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Locales List in Java
&lt;/h3&gt;

&lt;p&gt;You may wonder - “I have already created a Resource Bundle, can I assign it to a Locale?” - Yes! That’s where we use the Locale class.&lt;/p&gt;

&lt;p&gt;It provides ways to interact with the user’s system, such as using these methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
-&amp;gt; returns user’s default locale.

Using the system’s default localization on the app’s startup is a good practice. This method provides the user’s default locale, which you can use to load strings from ResourceBundle without the user even thinking about it.



```(String language_tag)```

 -&amp;gt; returns Locale for the language.

As you have already noticed, each Resource Bundle can be created for specific language tags. Sometimes you may need to differentiate between Australian English (en_AU) and American English (en_US) - so you can specify it using this method.



 ```(Locale.getAvailableLocales()```

-&amp;gt; returns an array of all installed locales.

We use this method when we want to know which locales are installed on the user’s JVM. You parse the list - you know what to serve to the user.

### Dates and Numbers

As I mentioned earlier, different countries may have different ways of presenting Dates and Numbers. Let's assume we have 1 million. In English, it should be formatted as 1,000,000; however, in German, it should be 1.000.000.

To format numbers, Locale-aware creates an instance of NumberFormat class:



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;NumberFormat nf_en = NumberFormat.getInstance(Locale.ENGLISH);&lt;/p&gt;

&lt;p&gt;String number_en = nf_en.format(1000000);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


-&amp;gt; 1,000,000



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;NumberFormat nf_ge = NumberFormat.getInstance(Locale.GERMAN);&lt;/p&gt;

&lt;p&gt;String number_ge = nf_ge.format(1000000);&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


-&amp;gt; 1.000.000

Same thing for dates. To format a date in Java, all you need to do is create an instance of DateFormat class:



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;DateFormat df_en = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.ENGLISH);&lt;/p&gt;

&lt;p&gt;String date_en = df_en.format(new Date());&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


-&amp;gt; Aug 7, 2022



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;DateFormat df_ge = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.GERMAN);&lt;/p&gt;

&lt;p&gt;String date_ge = df_ge.format(new Date());&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


-&amp;gt; 07.08.2022

The best part is instead of hard-coding the locale, we can use the user’s locale to format everything according to their culture!


## Context

So, you build the app and have all strings in English. Here’s the time you invite translators to your project. A lot of different people will look at the strings you wrote. How to build our resources so they will be translatable?

The concept of context plays a huge role in localization. Without it, some text may be translated poorly, but not because of the translator. Complex resources must have context attached!

If you name a string “string1,” - the translator will have no idea what this string’s for. Here’s a &amp;lt;a href="https://blog.crowdin.com/2019/11/05/no-context-no-quality-give-translators-context-to-get-better-translations/" target="_blank"&amp;gt;little reading material&amp;lt;/a&amp;gt;
 on why it’s crucial.

Long story short: be sure to correctly name all your strings in the .properties files so that people can know the context of it.


## Java i18n Application Example

We have talked about internalization only in theory. Let’s get to the point with our tutorial, where we will use all our new knowledge.

This tutorial will help to create a light Java project and implement internalization. All the project files will be available to fork &amp;lt;a href="https://github.com/danielsutts/i18n-with-Crowdin" target="_blank"&amp;gt;here&amp;lt;/a&amp;gt;.

### App Overview:

Our application is a small city visit tracker. I’ll call it simple - City Visit Tracker. The user enters their name and is presented with a few actions:

1.  Add a new city to the list.   
2.  Remove a city from the list.
3.  Edit an already added city (we all had this problem remembering the dates, didn’t we?).    
4.  Change the localization of the app.
5.  And, finally, exit the app.

I will use &amp;lt;a href="https://crowdin.com/on-demand-demo" target="_blank"&amp;gt;Crowdin&amp;lt;/a&amp;gt; for the translation of my resources. Using Crowdin - later in the tutorial.

First things first, let’s define the Client class.



```javascript

public class Client {
   private Locale userLocale;
   private final String username;
   private Map&amp;lt;City, Date&amp;gt; visitedCities;
   public Client(Locale userLocale, String username) {
       this.userLocale = userLocale;
       this.username = username;
   }
   public Locale getUserLocale() {
       return userLocale;
   }
   public void setUserLocale(Locale userLocale) {
       this.userLocale = userLocale;
   }
   public String getUsername() {
       return username;
   }  
   public void addCity(City city, Date dateVisited) {
       this.visitedCities.put(city, dateVisited);
   }
   public void removeCity(City city, Date dateVisited) {
       this.visitedCities.remove(city, dateVisited);
   }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want our user class to store all the cities visited, the user’s name and, most importantly, the user’s preferred locale. I’ve also added Getters and Setters so we can change the info to our needs.&lt;/p&gt;

&lt;p&gt;Next, let’s define the City class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;City&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;Locale&lt;/span&gt; &lt;span class="nx"&gt;cityLocale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;cityName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;cityCountry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;City&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Locale&lt;/span&gt; &lt;span class="nx"&gt;cityLocale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;cityName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;cityCountry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cityLocale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cityLocale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cityName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cityName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cityCountry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cityCountry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we’re allowing the user to put their cities to the list, let’s add all the cityLocale properties to the class, so we could even add the feature to translate city names in the future if we need to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;p&gt;Let’s create a new folder with the Message Bundle name and add a few .properties files. I want my app to have English, Polish, and Ukrainian. Therefore, I’m adding four files to the folder (the fourth one is the default).&lt;/p&gt;

&lt;p&gt;MessageBundle/&lt;/p&gt;

&lt;p&gt;/MessageBundle.properties&lt;/p&gt;

&lt;p&gt;/MessageBundle_en_US.properties&lt;/p&gt;

&lt;p&gt;/MessageBundle_pl_PL.properties&lt;/p&gt;

&lt;p&gt;/MessageBundle_uk_UA.properties&lt;/p&gt;

&lt;p&gt;For the sake of simplicity, we will not use the default file now, and I will start populating the resources in the en_US bundle.&lt;/p&gt;

&lt;p&gt;So, what do we want in our Resource Bundle?&lt;/p&gt;

&lt;p&gt;We need some menu messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;printAll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Print&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;cities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addCity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Add&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chooseAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Choose&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;removeCity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Remove&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;tracker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changeLocale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Change&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;localization&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Exit&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;editCity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Edit&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;existing&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want some basic words that we might use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;yes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Yes&lt;/span&gt;

&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;no&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;No&lt;/span&gt;

&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;City&lt;/span&gt;

&lt;span class="nx"&gt;word&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;

&lt;span class="nx"&gt;And&lt;/span&gt; &lt;span class="nx"&gt;here&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="nx"&gt;we&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;going&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;our&lt;/span&gt; &lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;welcome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Welcome&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;City&lt;/span&gt; &lt;span class="nx"&gt;Visit&lt;/span&gt; &lt;span class="nx"&gt;Tracker&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enterYourName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Enter&lt;/span&gt; &lt;span class="nx"&gt;your&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addCity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Add&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addCityName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Enter&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addCityDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Enter&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Successfully&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cityDeleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Successfully&lt;/span&gt; &lt;span class="nx"&gt;deleted&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cityEdited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Successfully&lt;/span&gt; &lt;span class="nx"&gt;edited&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forExample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;example&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;noChanges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;No&lt;/span&gt; &lt;span class="nx"&gt;changes&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;applied&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chooseLocale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Choose&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;available&lt;/span&gt; &lt;span class="nx"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tryAgain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Try&lt;/span&gt; &lt;span class="nx"&gt;again&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;noCities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;No&lt;/span&gt; &lt;span class="nx"&gt;cities&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="nx"&gt;yet&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chooseDelete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Choose&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chooseEdit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Choose&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newCityName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Enter&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;

&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newCityDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Enter&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Crowdin and Resources
&lt;/h3&gt;

&lt;p&gt;I added all the messages we needed. However, when developing an application, you want it to be Agile. &lt;a href="https://blog.crowdin.com/2020/12/08/development-and-localization-running-in-parallel-tips-for-developers/"&gt;Crowdin’s Github integration&lt;/a&gt; is available. I will go through integration.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Go to your  &lt;em&gt;Crowdin account&lt;/em&gt;  and  &lt;a href="https://accounts.crowdin.com/register"&gt;sign in&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt; Open &lt;em&gt;a new project&lt;/em&gt;.
&lt;/li&gt;
&lt;li&gt; Enter the info about your project.
&lt;/li&gt;
&lt;li&gt; Choose the &lt;strong&gt;Source language&lt;/strong&gt; and &lt;strong&gt;Target languages&lt;/strong&gt; (in our case, the source is English, and the target is Ukrainian and Polish.
&lt;/li&gt;
&lt;li&gt; Select “&lt;strong&gt;Choose integration&lt;/strong&gt;” in your &lt;em&gt;main menu&lt;/em&gt; -&amp;gt; &lt;em&gt;GitHub Personal&lt;/em&gt; -&amp;gt; &lt;em&gt;Authorize it with GitHub&lt;/em&gt;.
&lt;/li&gt;
&lt;li&gt; Choose &lt;em&gt;a repository&lt;/em&gt; you want to work with and &lt;strong&gt;select the branch&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt; You want to create a configuration file in your repository, where you need to specify the &lt;em&gt;/src/resources folder&lt;/em&gt; for source files.
&lt;/li&gt;
&lt;li&gt; You also want to specify the translated files folder. That way, your translators can give out their work piece-by-piece without needing to touch Git. Isn't it cool?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next step is to hire professionals to translate your text. But one more excellent feature of Crowdin allows us to translate our source files manually! Let’s do just that.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Go to &lt;strong&gt;Home&lt;/strong&gt; - &lt;em&gt;choose target language&lt;/em&gt; - press &lt;strong&gt;Translate&lt;/strong&gt;. Now you should see &lt;em&gt;Crowdin’s UI&lt;/em&gt; that allows you to choose the most appropriate translation of the Strings in our Source file.&lt;/li&gt;
&lt;li&gt;  Go through them and choose &lt;strong&gt;Suggestions below&lt;/strong&gt; (by the way, they are pretty good!).
&lt;/li&gt;
&lt;li&gt;  Once you’ve reached the end of both Ukrainian and Polish files, &lt;em&gt;go back&lt;/em&gt;, and press &lt;strong&gt;Proofread&lt;/strong&gt; to approve the translations. (this is usually a task of the localization director, so don’t be afraid to do it now - it’s only for practice :)
&lt;/li&gt;
&lt;li&gt;  In your &lt;em&gt;Home folder&lt;/em&gt;, press “&lt;strong&gt;Build &amp;amp; Download&lt;/strong&gt;” to download the translations you've just created. Now you can copy them into your folder and use them as custom internationalization of your application!&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Let’s Go On with Our Application
&lt;/h3&gt;

&lt;p&gt;We want our application to write, edit and remove cities. We also want it to list all the cities we’ve already added.&lt;/p&gt;

&lt;p&gt;With the use of DateFormat, ResourceBundle and Locale Java classes, let’s add these methods to our main class:&lt;/p&gt;

&lt;p&gt;To change the app’s locale, we simply print the user list of locales and try loading it from our ResourceBundle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;changeLocale&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.chooseLocale&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Arrays&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locales&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nx"&gt;Scanner&lt;/span&gt; &lt;span class="nx"&gt;scanner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;newLocale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;userResourceBundle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getBundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resources/MessageBundle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Locale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newLocale&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MissingResourceException&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.tryAgain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
       &lt;span class="nx"&gt;changeLocale&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we provide the user with the menu and wait for the input. Here you see only a few methods. Visit the app’s &lt;a href="https://github.com/danielsutts/i18n-with-Crowdin"&gt;GitHub page&lt;/a&gt; for more.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;Scanner&lt;/span&gt; &lt;span class="nx"&gt;scanner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="c1"&gt;// Print out the menu&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;menu.chooseAction&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0 - &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;menu.printAll&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1 - &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;menu.addCity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2 - &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;menu.removeCity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3 - &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;menu.editCity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;4 - &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;menu.changeLocale&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5 - &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;menu.exit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="err"&gt;…&lt;/span&gt;
   &lt;span class="c1"&gt;// If Menu Action is "Add City"&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;addCity&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Exception&lt;/span&gt; &lt;span class="nx"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.noChanges&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;       &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.tryAgain&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="err"&gt;…&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we define the addCity() method that adds city to our user’s repo. As you can see here, we use all the power of ResourceBundle, DateFormats and Locales to give the user the most authentic and internationalized experience.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;addCity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;throws&lt;/span&gt; &lt;span class="nx"&gt;ParseException&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Take user's input&lt;/span&gt;
   &lt;span class="c1"&gt;// Create a new City instance to fill it in&lt;/span&gt;
   &lt;span class="nx"&gt;Scanner&lt;/span&gt; &lt;span class="nx"&gt;scanner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;City&lt;/span&gt; &lt;span class="nx"&gt;newCity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;City&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="c1"&gt;// Add the user's locale to the City instance&lt;/span&gt;
   &lt;span class="nx"&gt;newCity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setCityLocale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLocale&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
   &lt;span class="c1"&gt;// Print out the city name prompt and set the new name&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.addCity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.addCityName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nx"&gt;newCity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setCityName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextLine&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
   &lt;span class="c1"&gt;// Print out the date prompt and set the new date&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.addCityDate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="c1"&gt;// Here, we transform the input data according to the user's locale&lt;/span&gt;
   &lt;span class="c1"&gt;// and save it as usual Date class&lt;/span&gt;
   &lt;span class="nx"&gt;DateFormat&lt;/span&gt; &lt;span class="nx"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;DateFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDateInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DateFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLocale&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.forExample&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nb"&gt;Date&lt;/span&gt; &lt;span class="nx"&gt;newDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextLine&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
   &lt;span class="nx"&gt;newCity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setVisitedDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newDate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addCity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newCity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="c1"&gt;// Tell user we saved a new city!&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.saved&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s define our pinnacle - the primary method of City Visit Tracker!&lt;/p&gt;

&lt;p&gt;We’ll have to define three static variables in the CityApplication.java file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kr"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;ResourceBundle&lt;/span&gt; &lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nx"&gt;locales&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[]{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en_US&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pl_PL&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;uk_UA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kr"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;final&lt;/span&gt; &lt;span class="nx"&gt;CityRepository&lt;/span&gt; &lt;span class="nx"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CityRepository&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ResourceBundle helps us switch between different l10n bundles. Locales tell us which languages are supported by our app. Repo is initialized to store the cities.&lt;/p&gt;

&lt;p&gt;From now on, all I need to do on the app’s startup is get the user’s default locale, print some welcome messages and start the menu() method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kr"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// Get user's default locale&lt;/span&gt;
   &lt;span class="c1"&gt;// Load ResourceBundle for the locale&lt;/span&gt;
   &lt;span class="nx"&gt;Locale&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Locale&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="nx"&gt;userResourceBundle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getBundle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resources/MessageBundle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="nx"&gt;Scanner&lt;/span&gt; &lt;span class="nx"&gt;scanner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.welcome&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.enterYourName&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nextLine&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userResourceBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message.hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUsername&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we’re done. Now is your turn! This app is a small example of what you can do with Java’s i18n and l10n bundles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this tutorial, we discovered what Java offers us in terms of localization and internationalization of our applications. I18n and l10n are extremely important when you want to provide the absolute best experience to the user.&lt;/p&gt;

&lt;p&gt;ResourceBundle class gives us an easy way to work with resources.&lt;/p&gt;

&lt;p&gt;Locale class gives us ways to interact with the user’s locale.&lt;/p&gt;

&lt;p&gt;DateFormat and NumberFormat allow us to format dates and numbers for the user’s locale.&lt;/p&gt;

&lt;p&gt;Don’t forget to make your translations agile and clean. Create a default package and let the translators and proofreaders do the work. We’ve also explored a way to automate the translation process with Crowdin – as you can see, it’s simple and fast.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>java</category>
    </item>
    <item>
      <title>Android App Localization: Key Steps</title>
      <dc:creator>Julia Herasymchuk</dc:creator>
      <pubDate>Thu, 11 Aug 2022 13:33:00 +0000</pubDate>
      <link>https://dev.to/crowdin/android-app-localization-key-steps-2k99</link>
      <guid>https://dev.to/crowdin/android-app-localization-key-steps-2k99</guid>
      <description>&lt;p&gt;You might be a beginner developer making your first Android app or an experienced programmer adding to your dozen or so other Android apps. But the main question is: who are you making this app for? This article will help you learn the key steps for the &lt;a href="https://crowdin.com/"&gt;localization of Android applications&lt;/a&gt; and reaching new markets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reasons to Localize Your Android App
&lt;/h2&gt;

&lt;p&gt;A leading media and information brand for the app industry, Business of Apps, says that Android is the most popular operating system in the world, &lt;a href="https://www.businessofapps.com/data/android-statistics/"&gt;with more than 2.5 billion active users&lt;/a&gt; in more than 190 countries. That is why Android apps are used by many people worldwide, so getting Android localization right has become an essential part of creating mobile apps. Localization of Android apps is the process of adapting a mobile app for people who speak different languages or live in different countries.&lt;/p&gt;

&lt;p&gt;You probably want your app to grow and be used by more people than just those in your local area. You want it to reach people on other continents and eventually go global. The problem is that not everyone speaks English. You will need to support more than one language sooner or later. It is an excellent reason to think about adding localization support to your Android app from the beginning.&lt;/p&gt;

&lt;p&gt;Localization can also be a part of app store optimization processes as a separate step for improving the visibility of your app. App localization is a lot about translation, but it's not the only thing. Localization includes a full review of how an app works to ensure it works well in each locale. Localizing app descriptions in the &lt;a href="https://play.google.com/store/games"&gt;Google Play app stores&lt;/a&gt; is also essential for worldwide app store optimization (&lt;a href="https://blog.crowdin.com/2021/02/11/smart-ways-to-approach-mobile-app-localization/#whats-next-aso-and-app-localization"&gt;ASO&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Even though localization takes time and work, it pays off in terms of downloads, new users, and money. A study by Distomo found that localized apps had &lt;a href="https://www.demandgenreport.com/features/demanding-views/there-s-a-language-for-that-translating-mobile-apps-and-content/"&gt;128% more downloads&lt;/a&gt; from the app store than apps that were not localized. Also, localized apps brought in 26 percent more money in each region. These numbers show that localizing your Android apps for a global audience is a great idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  Main Steps for Android App Localization
&lt;/h2&gt;

&lt;p&gt;By following best practices, you can make the process of localizing cheaper and less time-consuming while also making it easy to scale and maintain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prioritize locales and languages you’ll begin with
&lt;/h3&gt;

&lt;p&gt;When localizing Android apps, the most crucial choice is which markets to focus on. There is a cost to making your app work in a particular place. So, you shouldn't just try to make your Android app work in every language because you can.&lt;/p&gt;

&lt;p&gt;Also, the cost of making your app work in a different language is not the same in every case. It would help to consider how much money you will get back.&lt;/p&gt;

&lt;p&gt;Focus on the most common languages on the internet to get started. There are the five most-used languages on the internet. In order, the most common languages are English (25%), Chinese (19.8%), Spanish (8%), Arabic (4%) and Portuguese (4%).&lt;/p&gt;

&lt;p&gt;The three languages – English, Chinese, and Spanish – make up 55% of all the content on the internet, so they should be the first ones to be localized. When you are done localizing for these languages, you can move on to the next one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make layouts with localization in mind
&lt;/h3&gt;

&lt;p&gt;Different languages need different lengths for texts. When designing your app’s UI, you should consider how text grows and shrinks in different languages. It's typically recommended that UI elements have 30% more space in other languages.&lt;/p&gt;

&lt;p&gt;There are three main rules of design you should stick to&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; You shouldn't give UI elements fixed widths and heights (buttons, text fields, menus, labels, images). If not, when texts are translated into other languages, they might be cut off or have too many spaces.
&lt;/li&gt;
&lt;li&gt; You should put elements together in a way that makes sense. And put them in the same place every time. They need to be rearranged to make sense in the new languages. For example, if you have some numbered instructions on an Android app with buttons or other UI elements.&lt;/li&gt;
&lt;li&gt; Containers and wrappers should be able to change their sizes to fit the things they hold. A container can contain, for example, 3 buttons (you can find “ViewGroup” in the Android documentation). If the text is longer on another locale, then this container must correctly display the same 3 buttons without covering anything else.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you need to rearrange your layout to fit a specific language, you can create an alternative layout for that language (for example, res/layout-de/main.xml). However, doing this can make your app harder to maintain. It is better to create a single layout that is more flexible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Think about languages written and read from right to left
&lt;/h3&gt;

&lt;p&gt;Some languages are written and read from right to left. Hebrew and Arabic are good examples. You need to make layouts that can be turned around if necessary. It could be an expensive process that must go through many steps. That's why it's essential to think carefully about which languages you want to support before you start developing. Most of the time, modular design is thought to be the best way to go in this situation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Word wrappers and line breakers
&lt;/h3&gt;

&lt;p&gt;How words are split up is another crucial difference between languages. Even though space is used to separate words in many western languages, East Asian languages like Chinese and Japanese don't use spaces to do this.&lt;/p&gt;

&lt;p&gt;Consider the last example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;English&lt;/strong&gt;: You should localize your Android app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chinese&lt;/strong&gt;: 您應該本地化您的 Android 應用程序 (Disclaimer: it's text from Google Translate, I can't guarantee the accuracy of this translation)&lt;/p&gt;

&lt;p&gt;In Chinese, there are no spaces between words. The Chinese language is based on the separation of syllables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use fonts that can be applied to more than one language
&lt;/h3&gt;

&lt;p&gt;When choosing fonts for your texts, you need to be careful so that they look and feel the same in different languages. The font choice can significantly affect how easily the text reads. A few things should be kept in mind.&lt;/p&gt;

&lt;p&gt;But the most crucial thing for translation is whether or not fonts are Unicode or not (such as ASCII). The Universal Coded Character Set (UCS), a complete set of characters and glyphs from many languages, is used to make Unicode fonts. These characters are encoded to ensure they look the same on all platforms and systems. ASCII, on the other hand, is only used for one language. ASCII may look nice in English, but it can't be translated well. So, you should be careful to use a font that works with Unicode. Be careful because some fonts say they are Unicode, but they only work with some code points. It could cause trouble with languages.&lt;/p&gt;

&lt;p&gt;In different languages, the same font size may be hard to read differently. For example, 12px is easy to read in English, but the same size in Japanese could be hard to understand.&lt;/p&gt;

&lt;p&gt;For each language, you must change the font sizes on the fly. For that, you need to keep separate style sheets for each language.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do not hardcode text strings
&lt;/h3&gt;

&lt;p&gt;You shouldn't use hardcoded strings in layouts. For a beginner, this is very tempting. But this could be a big problem when it's time to localize your Android application into a different language.&lt;/p&gt;

&lt;p&gt;The good news is that Android Studio tells us about this. If you have already added hardcoded strings, Android Studio has an excellent way to add them to the string.xml file:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Right-click on the text and select &lt;strong&gt;Show Context Actions&lt;/strong&gt;, and then &lt;strong&gt;Extract resource string&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt; Press &lt;strong&gt;Alt&lt;/strong&gt;+&lt;strong&gt;Enter&lt;/strong&gt;. &lt;/li&gt;
&lt;li&gt; Click &lt;strong&gt;Extract resource string&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt; Then you'll see a dialog box. &lt;/li&gt;
&lt;li&gt; Give that string value a preferred name.&lt;/li&gt;
&lt;li&gt; Now, look at the &lt;code&gt;string.xml&lt;/code&gt; file and the layout page.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Put all the strings in strings.xml
&lt;/h3&gt;

&lt;p&gt;Don't hardcore any code strings when you develop your apps. Instead, put all your strings in a default &lt;code&gt;strings.xml file&lt;/code&gt; and mark them as resources. The strings in the &lt;code&gt;strings.xml&lt;/code&gt; file can then be quickly taken out, translated, and put back into your app (with the proper qualifiers) without having to change the code that was compiled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't make more text strings and resource files than you need
&lt;/h3&gt;

&lt;p&gt;You probably don't need to make a different version of every resource in your app for each locale. For example, the layout in the &lt;code&gt;res/layout/main.xml&lt;/code&gt; file might work in any locale, so you wouldn't need to make any other layout files.&lt;/p&gt;

&lt;p&gt;The default Android language for your app is American English. In &lt;code&gt;res/values/strings.xml&lt;/code&gt;, all of the American English spellings for the strings used by the app are listed.&lt;/p&gt;

&lt;p&gt;You should use British English spelling for a few crucial phrases. You want these alternative strings to be used when your app runs on a device in the United Kingdom. To do this, you could make a tiny file called &lt;code&gt;res/values-en-rGB/strings.xml&lt;/code&gt;with only the strings that should be different when the app runs in the U.K. The app uses the defaults for the rest of the strings, which are set in &lt;code&gt;res/values/strings.xml&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing String Localization with Localization Software Strings
&lt;/h2&gt;

&lt;p&gt;Strings are the most important objects In a localization process. Let's look at what we need to do to make strings work in different locales.&lt;/p&gt;

&lt;h3&gt;
  
  
  Follow the rules for UI strings in Android
&lt;/h3&gt;

&lt;p&gt;Make sure you pay close attention to how you talk to your users as you design and build your UIs. In general, use a style that is short, friendly, and to the point, and use the same style throughout your UIs.&lt;/p&gt;

&lt;p&gt;Read the &lt;a href="https://material.io/design/communication/writing.html#principles"&gt;Material Design&lt;/a&gt; suggestions for writing style and word choice and follow them.&lt;/p&gt;

&lt;p&gt;Also, always use the standard terms for Android, like Action Bar, Options Menu, System Bar, Notifications, and so on, whenever possible. Consistently using the correct Android terms make localization easier and the end product better for users. Additionally, you can use the &lt;a href="https://blog.crowdin.com/2018/05/18/using-glossary-to-keep-translations-swift-and-consistent/"&gt;glossary&lt;/a&gt;, which lets you create, store, and manage your project's terms in one place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give declared strings enough context
&lt;/h3&gt;

&lt;p&gt;When you declare strings in your strings.xml file, explain how they are used. This information is beneficial to the translator and translates better. It also helps you keep track of your strings better.&lt;/p&gt;

&lt;p&gt;Here's what we mean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;string name="countdown"&amp;gt;

&amp;lt;xliff:g id="time" example="5 days"&amp;gt;%1$s&amp;lt;/xliff:g&amp;gt; until holiday

&amp;lt;/string&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consider giving additional information, such as: When does it show up on the user's screen? What is the location of this text? Is it a button or a title? Should it be translated as a verb or as a noun?&lt;/p&gt;

&lt;p&gt;To stay flexible during localization, put in some time and provide context before the translation starts. In the long run, this will pay off. For example, the previous article summarizes all the different ways to &lt;a href="https://blog.crowdin.com/2019/11/05/no-context-no-quality-give-translators-context-to-get-better-translations/"&gt;give context during localization&lt;/a&gt;. So that you can be sure your translators always have a great place to work.&lt;/p&gt;

&lt;p&gt;For each language, you usually need at least one translator. Each of them might ask a dozen questions, and most of those questions are likely to be very similar. It would take you a long time to answer each one. &lt;a href="https://blog.crowdin.com/2020/01/27/a-closer-look-at-crowdin-mobile-sdk-extras-real-time-preview-and-screenshots/"&gt;Attaching screenshots&lt;/a&gt; is a very different thing.&lt;/p&gt;

&lt;p&gt;Screenshots will help all translators understand many things at once, as each translator would see a screenshot with the current string's location marked.&lt;/p&gt;

&lt;p&gt;A good idea would be to run the app version with Real-Time Preview set up on the Android Emulators you prefer to use. If you use &lt;a href="https://store.crowdin.com/appetize-app"&gt;Appetize.io&lt;/a&gt;, for example, give your team of translators the link to the app installed on the emulator so they can run it in their browsers. Or, give your translators the version they need, and they will put it on their devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mark parts of the message that don't need to be translated
&lt;/h3&gt;

&lt;p&gt;Often, strings have text that shouldn't be translated into other languages. Typical examples are a piece of code, a placeholder for a value, a special symbol, or a name. As you get your strings ready to be translated, look for text that shouldn't be changed and mark it, so the translator doesn't change it. Translators do not have to translate such strings because they can break the code.&lt;/p&gt;

&lt;p&gt;Use an &lt;code&gt;&amp;lt;xliff:g&amp;gt;&lt;/code&gt;placeholder tag to mark text that shouldn't be translated. Here's an example of a tag that makes sure the text "percent 1$s" doesn't get changed during translation, which could make the message wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;string name="countdown"&amp;gt;

&amp;lt;xliff:g id="time" example="5 days"&amp;gt;%1$s&amp;lt;/xliff:g&amp;gt; until holiday

&amp;lt;/string&amp;gt;`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you declare a placeholder tag, you should always add an id attribute that says what the placeholder is for. If your apps later change the value of the placeholder, make sure to add an example attribute to show how it should be used.&lt;/p&gt;

&lt;p&gt;You can see in Crowdin the highlighted text that translators should not translate. Additionally, they will receive a notification “ do not translate.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lPpYeK6F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ainza5na10uag4as5mit.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lPpYeK6F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ainza5na10uag4as5mit.png" alt="Image description" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Automate the Sync of Source Content and Translations?
&lt;/h3&gt;

&lt;p&gt;You may already know there's more to localization than downloading resource files, sending them to translators, and putting the translations into the codebase:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; It's a waste of time to do everything by hand.&lt;/li&gt;
&lt;li&gt; You must start downloading, sending, and integrating again if the source texts change or you get a new copy.&lt;/li&gt;
&lt;li&gt; If you send translators a spreadsheet with strings but no context, you can expect to get a lot of questions about the lack of context, and the number of target languages will multiply those questions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can set up several &lt;a href="https://store.crowdin.com/"&gt;integrations with Git tools &lt;/a&gt; in Crowdin. They all do a great job of keeping your systems' content in sync. For example, use integrations with &lt;a href="https://store.crowdin.com/github"&gt;GitHub&lt;/a&gt;, &lt;a href="https://store.crowdin.com/gitlab"&gt;GitLab&lt;/a&gt;, &lt;a href="https://store.crowdin.com/bitbucket"&gt;Bitbucket&lt;/a&gt;, and &lt;a href="https://store.crowdin.com/azure-repos"&gt;Azure Repos&lt;/a&gt;. It is also possible to &lt;a href="https://blog.crowdin.com/2020/04/30/add-localization-to-your-github-workflows-with-crowdin-action/"&gt;integrate with GitHub Actions&lt;/a&gt;. You can also use the &lt;a href="https://developer.crowdin.com/cli-tool/"&gt;Crowdin CLI&lt;/a&gt; or the &lt;a href="https://developer.crowdin.com/android-studio/#setup"&gt;Android Studio plugin&lt;/a&gt; to automatically upload source files to Crowdin and easily add translations to the codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hide duplicate strings to translate less
&lt;/h3&gt;

&lt;p&gt;Sometimes, the same strings will appear in different places on your app. For example, you may have two "Next" buttons that are represented by the button next and next button translation keys. These keys, on the other hand, will have the same translation Next. It means that these keys are essentially duplicates.&lt;/p&gt;

&lt;p&gt;If there are duplicate strings in your project, you can choose how the system should handle them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Show – translators will translate each instance (string) separately. Duplicated strings won’t be hidden.&lt;/li&gt;
&lt;li&gt;  Show, but auto-translate them – Duplicated strings will be automatically translated but will stay visible to translators. Once the string is translated, its translation is automatically shared between the duplicates. Translators may review and re-translate those strings if necessary.&lt;/li&gt;
&lt;li&gt;  Show within a version branch (regular detection) – duplicates will be hidden only between &lt;a href="https://support.crowdin.com/versions-management/"&gt;version branches&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  Show within a version branch (strict detection) – duplicates will be hidden only between version branches. &lt;/li&gt;
&lt;li&gt;  Hide (regular detection) – all duplicates will share the same translation.&lt;/li&gt;
&lt;li&gt;  Hide (strict detection) – all duplicates will share the same translation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regular duplicates detection: Crowdin only compares source texts when comparing strings.&lt;/p&gt;

&lt;p&gt;Strict duplicates detection: When Crowdin compares strings, it looks at both the keys and the source texts.&lt;/p&gt;

&lt;p&gt;Additionally, Crowdin offers a feature – &lt;a href="https://support.crowdin.com/tm-auto-substitution/"&gt;Auto-substitution&lt;/a&gt;. It is meant to make the Translation Memory (TM) more useful by suggesting translations that are a better match. With this feature, tags, HTML entities, placeholders, numbers, and other things that can't be translated are changed to the ones used in the source strings.&lt;/p&gt;

&lt;p&gt;Once the project owner or manager turns on the feature in the project settings, everyone who is part of the project can use it. If you are not the owner or manager of the project, ask someone who is to help you. To turn on Auto-substitution, go to Project Settings, click on the General tab, scroll down to the Translation Memory section, and check the Enable Auto-Substitution box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Localization of a Mobile App without Resource Files
&lt;/h2&gt;

&lt;p&gt;Usually, the localization of an app starts when the resource files are sent to translators, either by email (please don’t)) or automatically. The resource file comes first, and you can move on to localization.&lt;/p&gt;

&lt;p&gt;Let's switch this up and send strings directly from your design tool (like Figma, Sketch, or Adobe XD) to be translated. Crowdin's design and development teams can work on UI localization without using resource files. It’s a new way to do localization.&lt;/p&gt;

&lt;p&gt;Designers working on prototypes in Adobe XD, Figma, or Sketch can send strings to be translated by using keys and rules for dividing up text.&lt;/p&gt;

&lt;p&gt;Because each localization string has its unique identifier, it's easy for development teams to add the original and translated content to the codebase.&lt;/p&gt;

&lt;p&gt;Also, if the source files in Crowdin are in a format other than Android XML and Strings, engineers can run the custom exporters and download files in the correct format. They can use either the &lt;a href="https://blog.crowdin.com/2020/08/05/announcing-the-new-API-2.0/"&gt;Crowdin API&lt;/a&gt; or the Crowdin download targets command in &lt;a href="https://blog.crowdin.com/2020/12/03/what-is-new-at-crowdin-november-2020-roundup/"&gt;CLI versions 3.4.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://support.crowdin.com/advanced-project-setup/#bundles"&gt;Crowdin Bundles&lt;/a&gt; lets you upload a single source file (like Android XML) to your project, translate it, and then use bundles to export translations for multiple platforms by creating different file formats (Android XML for the Android app). You can add bundles and set them up so that you can export groups of strings in one of the file formats.&lt;/p&gt;

&lt;p&gt;Crowdin's integration with design tools (&lt;a href="https://store.crowdin.com/figma"&gt;Figma&lt;/a&gt;, &lt;a href="https://store.crowdin.com/sketch"&gt;Sketch&lt;/a&gt;, or &lt;a href="https://store.crowdin.com/adobe-xd-plugin"&gt;Adobe XD&lt;/a&gt;) is an excellent way for designers to preview translated mockups, change them if needed, or let engineers know about the parts that should be scaled.&lt;/p&gt;

&lt;p&gt;Find out more about the Crowdin &lt;a href="https://crowdin.com/teams/designers"&gt;plugins for design teams&lt;/a&gt; and how they make it easier to &lt;a href="https://blog.crowdin.com/2021/01/27/best-practices-for-ui-localization/"&gt;localize user interfaces&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crowdin SDK for Android apps
&lt;/h2&gt;

&lt;p&gt;You don't have to put out a new version of the app on Google Play every time you want to add a new language. Install &lt;a href="https://developer.crowdin.com/sdk-android/"&gt;Crowdin SDK&lt;/a&gt; on your app, and your &lt;a href="https://crowdin.com/"&gt;Crowdin&lt;/a&gt; project will send you ready-to-go translations immediately. Three new features will make getting the latest translations directly from your Crowdin project's distribution, automatically upload screenshots, and see what translations look like in the app in real-time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Over-The-Air Content Delivery&lt;/strong&gt;&lt;br&gt;
Crowdin can send new translations to your app over the air, so you don't have to update your app on Google Play. The Crowdin SDK for Android has two extra parts that you can connect: a real-time preview of the translation and an easy way to upload and tag screenshots.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-Time Preview&lt;/strong&gt;&lt;br&gt;
Crowdin lets translators see an instant preview of the translations they make on their app. LQA (linguistic quality assurance) should be made easier so your team can check the translated content in context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Screenshots&lt;/strong&gt;&lt;br&gt;
Project owners and managers can take screenshots in the app version where this component is turned on. Screenshots will automatically be added to the project if the source strings are marked.&lt;/p&gt;

&lt;h2&gt;
  
  
  You Know How to Do Localization Now
&lt;/h2&gt;

&lt;p&gt;We've gone over everything you need to think about when you start tailoring your app for your target market. There are two common myths. The first is to think everyone will use your app in English. The second would be that you can handle localization without technology.&lt;/p&gt;

&lt;p&gt;Crowdin knows that the &lt;a href="https://blog.crowdin.com/2021/02/11/smart-ways-to-approach-mobile-app-localization/"&gt;localization of your mobile app&lt;/a&gt; is a vital part of growing your market share and sales in other countries. We make it easy for you to localize your Android app, so you don't have to deal with strings and spreadsheets.&lt;/p&gt;

&lt;p&gt;Sign up for a &lt;a href="https://accounts.crowdin.com/register"&gt;Crowdin&lt;/a&gt; or &lt;a href="https://accounts.crowdin.com/workspace/create"&gt;Crowdin Enterprise&lt;/a&gt; account to get started. Book a &lt;a href="https://crowdin.com/demo-request"&gt;personal demo&lt;/a&gt; with our tech manager if you'd like to learn more best practices and talk about the unique ways you work.&lt;/p&gt;

</description>
      <category>android</category>
      <category>localization</category>
      <category>mobile</category>
      <category>design</category>
    </item>
  </channel>
</rss>
