<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Siarhei Razanau on Medium]]></title>
        <description><![CDATA[Stories by Siarhei Razanau on Medium]]></description>
        <link>https://medium.com/@razanau?source=rss-76e0032ec1a6------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*sqpGbx5j-pgopsPXy1K5aw.jpeg</url>
            <title>Stories by Siarhei Razanau on Medium</title>
            <link>https://medium.com/@razanau?source=rss-76e0032ec1a6------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 13 Jul 2026 10:28:19 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@razanau/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[All You Need to Know for iOS App Localization: Tips, Tricks, and Best Practices]]></title>
            <link>https://medium.com/@razanau/ios-app-localization-4ba78ee8ba30?source=rss-76e0032ec1a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/4ba78ee8ba30</guid>
            <category><![CDATA[development]]></category>
            <category><![CDATA[localization]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swiftui]]></category>
            <dc:creator><![CDATA[Siarhei Razanau]]></dc:creator>
            <pubDate>Mon, 03 Feb 2025 21:19:11 GMT</pubDate>
            <atom:updated>2025-02-03T21:19:11.701Z</atom:updated>
            <content:encoded><![CDATA[<h3><strong>All You Need to Know for iOS App Localization</strong></h3><h4>Tips, Tricks, and Best Practices</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*66fkmgicSgjw5JFEbThK0Q.png" /></figure><p>Hi, my name is <a href="https://www.linkedin.com/in/siarhei-razanau">Siarhei</a>, and I’m a Software Engineer with over 10 years of experience in iOS app development. During my career, I have worked with many teams to create multilingual apps for different audiences and industries. This experience has taught me a lot about the tools and services used for localization and the common challenges developers face. Over the years, localization has become much easier and cheaper, making it more accessible than ever.</p><p>However, even when using professional translators or AI tools, developers play an important role in the localization process. We need to provide clear and well-structured text for translation and ensure that all content is displayed correctly in the app. I’ve seen skilled developers make mistakes because they didn’t know the differences between languages. These mistakes often go unnoticed because everything looks correct in their own language.</p><p>In this article, I’ll share simple tips and best practices to help developers create apps that feel natural for users, no matter their language. This guide will be helpful for both new and experienced developers, not just for iOS but for all Apple platforms. Let’s explore how we can make localization better and easier for everyone.</p><h3><strong>String vs. LocalizedStringKey</strong></h3><p>One of the first things to understand is how strings are handled. Let’s start with two examples:</p><pre>let string = &quot;Hello World!&quot;<br>Text(string)</pre><pre>Text(&quot;Hello World!&quot;)</pre><p>At first glance, these examples might seem identical, but they behave differently because of the types of data passed to <strong>Text</strong>. In the first example, the constant string is implicitly inferred to be of type String because it’s initialized with a string literal. When passed to Text, the String object is used directly, and the text “Hello World!” is displayed as plain text.</p><p>In the second example, the string literal “Hello World!” is directly passed to <strong>Text</strong>. Here, the literal is treated as an instance of <strong>LocalizedStringKey</strong>, because <strong>Text</strong> by default expects an object of type <strong>LocalizedStringKey</strong>. In this case, “Hello World!” is not treated as a value but as a key. The result is determined as follows:</p><ul><li>If the key “Hello World!” exists in the default localization table, the corresponding value will be displayed.</li><li>If no entry is found for the key, Xcode may automatically add this string to the default String Catalog file (if this option is enabled in Build Settings). In this case, the key itself will be displayed.</li></ul><p>If you do not want to use the default localization table, you can specify a custom table with the <strong>tableName</strong> parameter. You can also define the source of localization files by using the <strong>bundle</strong> parameter.</p><pre>Text(&quot;Hello World!&quot;, tableName: &quot;CustomLocalizations&quot;, bundle: .main)</pre><p>If you want to make sure that your string is not added to the String Catalog file and is displayed as-is, you can use</p><pre>Text(verbatim: &quot;Hello World!&quot;)</pre><p>or explicitly pass a <strong>String</strong> object.</p><p>The same logic with <strong>LocalizedStringKey</strong> applies to other UI elements in SwiftUI. Always be careful about the type of object that a view expects to display.</p><p>If your strings are initialized outside of views, such as in business logic, or if you work with UIKit or AppKit, you can still use translations and automatically add strings to String Catalog files. To do this, use the following approach:</p><pre>let string = String(localized: &quot;Hello World!&quot;)</pre><p>If you want to use a non-default localization file, you can specify it like this:</p><pre>let string = String(<br>    localized: &quot;Hello World!&quot;, <br>    table: &quot;CustomLocalizations&quot;, <br>    bundle: .main)</pre><p>Understanding this behavior is critical for ensuring that strings are localized correctly. It also highlights the importance of carefully managing your localization files to avoid unexpected results.</p><h3>Providing Context</h3><p>Providing translators with context is essential for ensuring accurate translations. Whether your app is translated by a human or AI, a lack of context can lead to incorrect results. This is especially important for short strings, where it might be impossible to determine the part of speech or the intended meaning without additional information. To avoid such issues, you can add an optional comment to explain the string’s purpose:</p><pre>Text(&quot;Hello World!&quot;, comment: &quot;Comment for translator&quot;)</pre><pre>let string = String(<br>    localized: &quot;Hello World!&quot;,<br>    comment: &quot;Comment for translator&quot;)</pre><p>The comment you provide will automatically be included with the string in the String Catalog file.</p><p>Using a string as both the key and value for the main language is convenient, but it can sometimes lead to problems in other languages. For example, imagine a screen with a title “Archive” and a button labeled “Archive” that moves items into the archive. In code, this might look like:</p><pre>Text(&quot;Archive&quot;)<br><br>Button(&quot;Archive&quot;)</pre><p>Both the button and the title would reference the same string in the localization table. While this might work in some languages, in many others, the noun and verb forms of “Archive” would require different translations.</p><p>If you notice that identical strings have different meanings depending on their context, it’s better to create separate keys for them. This can be done as follows:</p><pre>let archiveTitle = String(<br>    localized: &quot;archive.label&quot;,<br>    defaultValue: &quot;Archive&quot;,<br>    comment: &quot;Name of the Archive folder in the sidebar&quot;)<br>// EN: Archive<br>// ES: Archivado<br>// RU: Архив<br><br>let archiveAction = String(<br>    localized: &quot;archive.menuItem&quot;,<br>    defaultValue: &quot;Archive&quot;,<br>    comment: &quot;Menu item title for moving the email into the Archive folder&quot;)<br>// EN: Archive<br>// ES: Archivar<br>// RU: Архивировать</pre><p>By creating unique keys for strings with different contexts, you ensure that translations are accurate and meaningful for all languages.</p><h3><strong>Pluralization</strong></h3><p>Localizing strings with numerical variables is a common task, but it can also be a source of issues if not done correctly. Often, you might see code like this:</p><pre>Text(count == 1 ? &quot;\(count) apple&quot; : &quot;\(count) apples&quot;)</pre><p>While this may work for English, it poses significant challenges for other languages. Words that depend on numbers often change based on complex grammatical rules. For example, in Russian:</p><ul><li>1 яблок<strong><em>о</em></strong></li><li>2 яблок<strong><em>а</em></strong></li><li>5 яблок</li><li>20 яблок</li><li>21 яблок<strong><em>о</em></strong></li></ul><p>These variations follow specific pluralization rules, which can differ greatly across languages. The complete set of these rules is available on the <a href="https://cldr.unicode.org/">CLDR Unicode website</a>.</p><p>To handle pluralization correctly, you can start by writing:</p><pre>Text(&quot;\(count) apples&quot;)</pre><p>Then, in your String Catalog file, right-click on the string and select <strong>“</strong>Vary by Plural<strong>”</strong> from the context menu. After enabling pluralization, update the fields for your main language. For example, in English:</p><ul><li>In the “One<strong>”</strong> field, enter <em>%lld apple</em>.</li><li>In the “Other<strong>”</strong> field, enter <em>%lld apples</em>.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_isMAZ3LrUi2WKuBXTJfGw.png" /></figure><p>For each supported language, additional fields will appear, allowing you to provide translations that follow the CLDR rules.</p><p>Another way to handle pluralized strings is by using automatic inflection:</p><pre>Text(&quot;^[\(count) apple](inflect: true)&quot;)</pre><p>The word will automatically change based on the value of “count”. This works for both countable and uncountable nouns:</p><pre>let count = 3<br>Text(&quot;^[\(count) person](inflect: true)&quot;)   // 3 people<br>Text(&quot;^[\(count) company](inflect: true)&quot;)  // 3 companies<br>Text(&quot;^[\(count) deer](inflect: true)&quot;)     // 3 deer</pre><p>While this method works well, it has a significant limitation: it does not support all languages. You can check if a language is supported using the following code:</p><pre>let canInflect = InflectionRule.canInflect(language: &quot;&lt;language_code&gt;&quot;)<br>// or<br>let canInflect = InflectionRule.canInflectPreferredLocalization</pre><p>Currently supported languages are:</p><ul><li><strong>iOS 16:</strong> English, Italian, Spanish, Portuguese, French</li><li><strong>iOS 17:</strong> English, Italian, Spanish, Portuguese, French, German</li><li><strong>iOS 18:</strong> English, Italian, Spanish, Portuguese, French, German, Korean, Hindi</li></ul><p>On iOS 15, the <strong>canInflect</strong> function returns <strong>true</strong> for English, Italian, Spanish, Russian, and Swedish, but in reality, only English and Spanish are supported.</p><p>Due to the limited support for this feature, I would still recommend using the manual approach with <strong>String Catalog</strong> to ensure broader language compatibility.</p><h3><strong>Formatting Data</strong></h3><p>It’s common to see code like this:</p><pre>Text(&quot;\(price)$&quot;)</pre><p>While this might work in specific cases, it fails to account for how data is displayed in different regions. Even countries that share the same language can use different formats for various types of data. Thankfully, Apple has already implemented logic to handle these variations.</p><p>The <strong>formatted</strong> function is a powerful tool that adapts values based on the current locale. It supports translations for unit names, including plural forms, and can be used for a wide range of data. For example, prices, percentages, and dates can be formatted automatically as follows:</p><pre>let currency = 1390.5.formatted(.currency(code: &quot;USD&quot;))<br>// en_US: $1,390.50<br>// es_ES: 1390,50 US$<br>// ru_RU: 1 390,50 $<br><br>let percent = 25.formatted(.percent)<br>// en_US: 25%<br>// es_ES: 25 %<br>// tr_TR: %25<br><br>let date = Date().formatted(.dateTime)<br>// en_US: 1/25/2025, 8:10 PM<br>// es_ES: 25/1/2025, 20:10<br>// ru_RU: 25.01.2025, 20:10</pre><p>Another example is the formatting of lists, which can vary depending on the language. Apple’s tools make it easy to handle these differences:</p><pre>let list = [&quot;iPhone&quot;, &quot;iPad&quot;, &quot;Apple Watch&quot;].formatted(.list(type: .and))<br>// en_US: iPhone, iPad, or Apple Watch<br>// es_ES: iPhone, iPad y Apple Watch<br>// ru_RU: iPhone, iPad и Apple Watch</pre><p>Apple also provides a way to display most physical units of measurement in the correct format for any region using the <strong>Measurement</strong> structure. For example, to display temperature:</p><pre>let measurement = Measurement(<br>    value: 24,<br>    unit: UnitTemperature.celsius)<br>let temperature = measurement.formatted(.measurement())<br>// en_US: 75.2°F<br>// es_ES: 24°C<br>// ru_RU: 24 °C</pre><p>The unit parameter supports various types of measurements. Here’s the full list:</p><ul><li><strong>UnitAcceleration</strong>: Unit of measure for acceleration.</li><li><strong>UnitAngle</strong>: Unit of measure for planar angle and rotation.</li><li><strong>UnitArea</strong>: Unit of measure for area.</li><li><strong>UnitConcentrationMass</strong>: Unit of measure for concentration of mass.</li><li><strong>UnitDispersion</strong>: Unit of measure for dispersion.</li><li><strong>UnitDuration</strong>: Unit of measure for duration of time.</li><li><strong>UnitElectricCharge</strong>: Unit of measure for electric charge.</li><li><strong>UnitElectricCurrent</strong>: Unit of measure for electric current.</li><li><strong>UnitElectricPotentialDifference</strong>: Unit of measure for electric potential difference.</li><li><strong>UnitElectricResistance</strong>: Unit of measure for electric resistance.</li><li><strong>UnitEnergy</strong>: Unit of measure for energy.</li><li><strong>UnitFrequency</strong>: Unit of measure for frequency.</li><li><strong>UnitFuelEfficiency</strong>: Unit of measure for fuel efficiency.</li><li><strong>UnitIlluminance</strong>: Unit of measure for illuminance.</li><li><strong>UnitInformationStorage</strong>: Unit of measure for quantities of information.</li><li><strong>UnitLength</strong>: Unit of measure for length.</li><li><strong>UnitMass</strong>: Unit of measure for mass.</li><li><strong>UnitPower</strong>: Unit of measure for power.</li><li><strong>UnitPressure</strong>: Unit of measure for pressure.</li><li><strong>UnitSpeed</strong>: Unit of measure for speed.</li><li><strong>UnitTemperature</strong>: Unit of measure for temperature.</li><li><strong>UnitVolume</strong>: Unit of measure for volume.</li></ul><p>The <strong>formatted</strong> function is versatile and can be applied to various types of data, such as numbers, dates, times, intervals, and even people’s names. I recommend exploring its parameters and capabilities. It not only simplifies localization but also saves time by automating data formatting and conversion logic.</p><h3><strong>Localizing User Interface</strong></h3><p>Localization goes beyond adapting text — it’s about ensuring that your app feels natural and intuitive for users in different regions. People may interact with your app differently depending on their language and cultural norms.</p><p>For example, in languages like Arabic or Hebrew, the interface is read from right to left (RTL). Fortunately, standard interface components in Apple’s frameworks already support RTL layouts. To ensure your app handles this seamlessly, use <strong>leading</strong> and <strong>trailing</strong> constants instead of <strong>left</strong> and <strong>right</strong> when designing your interface. Only use <strong>left</strong> and <strong>right</strong> constants for components that should remain in fixed positions regardless of the language.</p><p>Another important factor to consider is font compatibility. While custom fonts can be used, I recommend the standard San Francisco font family because it is highly optimized for various languages, provides excellent readability, and ensures proper support for a wide range of characters and symbols. Custom fonts, on the other hand, may not support certain symbols or scripts required for some languages. If your design requires a custom font, ensure that all texts are thoroughly tested across all supported languages to avoid display issues.</p><p>Images can also be localized through the asset catalog. While it’s best to avoid placing text directly on images, there are cases where you may need to show different images or icons for specific regions. Apple makes this easy with localized asset variants.</p><p>For icons, I highly recommend using SF Symbols. These symbols automatically adapt to different languages and provide consistent visuals across your app.</p><p>By considering these aspects of localization, you can create an app that not only displays the right text but also feels tailored to users from any part of the world.</p><h3><strong>Styling Text Without Breaking Localization</strong></h3><p>When styling text, it’s essential to keep the entire string intact. A common mistake is splitting a sentence into multiple <strong>AttributedString</strong> segments and then concatenating them:</p><pre>var hello = AttributedString(localized: &quot;Hello&quot;)<br>hello.font = .system(size: 12)<br>hello.foregroundColor = .black<br><br>var world = AttributedString(localized: &quot; World&quot;)<br>world.font = .system(size: 17)<br>world.foregroundColor = .white<br><br>let result = hello + world</pre><p>At first glance, this approach may seem reasonable, but in reality, it creates two separate strings in the String Catalog. This can lead to translation issues because word forms depend on each other in many languages. The number and order of words may also change depending on the language. Additionally, in some cases, you may need to style individual letters rather than entire words, making proper localization even more challenging.</p><p>Instead of splitting strings, you can use built-in Markdown formatting or external libraries like <a href="https://github.com/gonzalezreal/swift-markdown-ui">swift-markdown-ui</a> or <a href="https://github.com/Rightpoint/BonMot">BonMot</a>. These tools allow you to apply different styles to parts of a string while keeping it as a single translatable unit.</p><p>If you prefer not to add an extra dependency or need more fine-grained control over text formatting, you can use <strong>custom attributes</strong> in <strong>AttributedString</strong>. While this requires additional code, it allows you to apply styles dynamically without breaking localization.</p><p>For example, a localized string might look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xVSG174NHcxaUuzFsvVrnw.png" /><figcaption>^[Fast](rainbow: ‘fun’) &amp; ^[Delicious](rainbow: ‘extreme’) Food</figcaption></figure><p>How to implement custom attributes is beyond the scope of this article, but you can check out <a href="https://developer.apple.com/documentation/foundation/data_formatting/building_a_localized_food-ordering_app/">Apple’s example</a>, which also demonstrates formatting options for other types of data.</p><h3><strong>Conclusion</strong></h3><p>I currently live in a country where I don’t speak the national language. Seeing even partial localization in local apps and websites makes a big difference for me. Even machine translation helps a lot because it allows me to guess what will happen when I click a button and feel more confident that I won’t accidentally do something wrong.</p><p>I highly recommend translating your apps into as many languages as possible. It can be a competitive advantage, helping you reach more users and stand out in the market. I understand that hiring professional translators can be expensive, but for secondary languages, using AI is a cost-effective solution. For just a few dollars, you can add support for a new language.</p><p>The key is to provide enough context for translations, which greatly improves its quality. You can do this manually or use existing services designed for localization. I’ve tried many of these services and eventually built my own macOS app that translates strings using context from comments. If you find it helpful, I’d be very glad. You can check it out <a href="https://apple.co/40XJSoD">here</a>.</p><p>I’d also love to hear your thoughts in the comments. It would be great if you shared insights about the unique aspects of your native language and any additional localization tips you might have.</p><p>Thank you for reading to the end!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4ba78ee8ba30" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[AI-Driven Localization for Xcode Projects]]></title>
            <link>https://medium.com/@razanau/ai-driven-localization-for-xcode-projects-da36bc6bb93c?source=rss-76e0032ec1a6------2</link>
            <guid isPermaLink="false">https://medium.com/p/da36bc6bb93c</guid>
            <category><![CDATA[localization]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[string-catalog]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Siarhei Razanau]]></dc:creator>
            <pubDate>Mon, 26 Aug 2024 19:57:04 GMT</pubDate>
            <atom:updated>2024-08-26T19:57:04.055Z</atom:updated>
            <content:encoded><![CDATA[<h4>My name is Siarhei, and I’ve been developing iOS apps for over 10 years. Throughout this time, I’ve seen how localization has traditionally been a luxury only large companies with big budgets could afford. I decided to harness the power of AI to make this process more accessible. In this article, I’ll take you through my journey of trying to tame AI for app localization and share the outcome of my efforts.</h4><p>For solo developers, small teams, and startups, localizing an app can be a tough and expensive challenge. Hiring professional translators often comes at a high cost, making it difficult for many to bring their products to a global market. However, reaching a worldwide audience is crucial because it allows you to test your app in different regions and expand your user base. Machine translation might seem like a quick and cheap solution, but the quality often isn’t good enough. Traditional machine translators usually miss the full context, leading to awkward and confusing translations that can frustrate users. However, with the rise of advanced AI models like GPT, this is starting to change. Now, we can use AI to translate apps by providing the context needed to create more accurate and meaningful translations. While the results aren’t perfect yet, they’re good enough to allow users to comfortably interact with the app in their native language.</p><p>For my projects, I initially used ChatGPT to help with localization. I would manually copy strings from my Xcode project into the chat, explaining the context. After receiving the translations, I’d paste the results back into the strings catalog in Xcode. This process was incredibly monotonous and time-consuming. I assumed someone must have already automated this process, so I started searching for existing solutions. I found quite a few tools, both free and paid, that attempted to address this problem, but none of them fully met my needs. Most tools simply translated the strings without considering the context, which defeats the purpose of using modern AI. As a result, the translations were often inaccurate or awkward. Other tools had limitations in supporting different types of strings. For instance, they struggled with complex plural strings. But the biggest issue for me was that my projects included strings with Markdown or HTML formatting. These are essential when you need to emphasize certain words within a sentence that cannot be split into different strings. During translation, the formatting was often lost, which was unacceptable. After searching and not finding a solution that truly met my needs, I decided to create my own translation tool.</p><p>When I started building the tool, I quickly faced the difficulties of working with AI, especially with something called AI “hallucinations”. I learned firsthand that, even with straightforward requests, AI can sometimes produce completely unacceptable responses. This experience led me to explore prompt engineering more deeply and try different techniques to make the results more reliable. Here are some key insights I gathered along the way:</p><ol><li>AI models like those from OpenAI can’t read your mind. They’re designed to always provide some kind of response, even if it’s not exactly what you intended. The models aim to please, but they can only work with what you give them. Therefore, it’s crucial to craft your prompts as precisely as possible to guide the AI toward the desired outcome.</li><li>While it’s essential to be precise, I’ve found that overly detailed and lengthy prompts can sometimes overwhelm the AI, causing it to miss or ignore certain requirements. It’s often more effective to break down a large task into smaller, more focused subtasks. This way, the AI can concentrate on one specific aspect at a time, leading to more accurate and consistent results.</li><li>I also noticed that AI understands instructions much better when provided with examples. By structuring your prompt with clear examples of the desired format or outcome, you can significantly improve the quality of the responses. Think of it as having a conversation with the AI — show it what you mean, rather than just telling it.</li><li>Fine-tuning the model can be a powerful way to shorten prompts and teach AI concepts that are hard to convey purely through text. However, it’s essential to be very careful with the data you use for training. During fine-tuning, the model will prioritize this new information over its base knowledge, which can lead to worse performance on tasks that weren’t covered by the training data.</li><li>Interestingly, I discovered that older models like GPT-3.5 tend to be more straightforward and are excellent at executing short, clear tasks. On the other hand, the newer models, like GPT-4o and GPT-4o mini, might add extra information even if you didn’t ask for it, but they handle more complex and longer prompts better. They also tend to ignore fewer requirements, making them more reliable for intricate tasks.</li><li>After receiving a response from the AI, you can ask it to review its own output to ensure that all requirements have been met. This step can help catch any missed details or errors that may have slipped through.</li><li>Another technique is to send the same prompt multiple times, either to the same model or different models, and then ask the AI to vote on the best response. This approach helps filter out AI hallucinations or results that do not meet all conditions.</li><li>Finally, even when you think you’ve crafted the perfect prompt, it’s essential to test it across a large number of examples. Sometimes, what works well on a few test cases may perform poorly on a broader set of data. Thorough testing is key to ensuring consistent results.</li></ol><p>Through a combination of these approaches, I was able to significantly reduce AI hallucinations and improve the accuracy of the results. To translate a single string into one language, I need to provide a fairly lengthy prompt with examples and perform multiple requests to refine the output and filter out incorrect results. While this process makes each translation more costly than I initially expected, it is still incomparably cheaper than using human translators.</p><p>I also spent far more time developing this tool than I originally anticipated. However, the result is a highly useful utility that effectively meets my needs. While it may not be a perfect translation tool, it is good enough to launch apps in different markets. Given its usefulness, I decided to package it into a convenient macOS application and make it available on the <a href="https://apple.co/4fZacnt">App Store</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*G6JPS8bjvPjaZCcB8_jodg.png" /></figure><p>The application is designed specifically for translating Xcode projects that use the modern <a href="https://developer.apple.com/documentation/xcode/localizing-and-varying-text-with-a-string-catalog">String Catalog files</a> to manage strings. It supports all types of strings, including complex plural strings and device-specific variations. My goal was to automate as much of the process as possible while still allowing full control when needed. One of the key features is that there’s no need to export or import strings manually. Simply open your Xcode project in the app, and all strings and their statuses will be automatically synchronized.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IilQHGNmvyVQXJFvgCs5rQ.jpeg" /></figure><p>From there, you can click the “Run” button to automatically translate all untranslated strings into the languages supported by your project. You can choose which AI model to use for translations. As I mentioned earlier, for complex tasks, it’s sometimes better to use more advanced (and expensive) models, but in most cases, the less expensive ones work just fine. I’ve added an automatic mode that dynamically selects the model based on the type of string and its context. However, you can also experiment and manually select the model that works best for your needs. In the future, I plan to add more models, not just from OpenAI.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NWRo-qg-bHH__YrRc1Xovw.jpeg" /></figure><p>You can also choose which strings to translate based on their status and select the languages to which they should be translated.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nlnSQA7-HI1bwpyP5EdW2w.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KhgdSIhEdE4PT1f5LdP2wQ.jpeg" /></figure><p>If you prefer to have more control over the translation of each string, you can translate them one by one for all languages or for a specific language using the context menu.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fXZUgy54wbznYDNxTZRwBA.jpeg" /></figure><p>Additionally, if needed, you can manually translate or edit the text to ensure it meets your exact requirements.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*K4WxEXQv_mQnmrBMmqDAFA.jpeg" /></figure><p>Regardless of who or what is localizing your app, it’s a best practice to include comments with your strings to give more context to the translators. My application will pass these comments along to the AI to help better explain the context. While comments are not mandatory, they can greatly enhance the accuracy of the results. For example, in English, a word can sometimes function as both a noun and a verb, while in other languages, these forms might look very different. In such cases, providing additional context through comments is crucial to ensure the translation is accurate. Without this extra information, the AI or a human translator might misinterpret the intended meaning, leading to errors in the localized version.</p><pre>let archiveFolderName = String(<br>    localized: &quot;Archive.label&quot;,<br>    defaultValue: &quot;Archive&quot;,<br>    comment: &quot;Name of the Archive folder in the sidebar&quot;)<br><br>// EN: Archive<br>// ES: Archivado<br>// RU: Архив</pre><pre>let archiveMenuItemTitle = String(<br>    localized: &quot;Archive.menuItem&quot;,<br>    defaultValue: &quot;Archive&quot;,<br>    comment: &quot;Menu item title for moving the email into the Archive folder&quot;)<br><br>// EN: Archive<br>// ES: Archivar<br>// RU: Архивировать</pre><p>By including clear and concise comments, you can help the AI understand the specific use of each string, whether it’s a button label, a menu item, or an error message. This simple step can make a big difference in the overall quality of the localized app.</p><p>Thank you for taking the time to read through this article. If you find my app useful, I invite you to <a href="https://apple.co/4fZacnt">download it</a> from the App Store and give it a try. I have plenty of ideas on how to improve the tool, but I’m always open to feedback. If you have any comments or suggestions, feel free to reach out to me via <a href="mailto:s.razanau@icloud.com">email</a>. Your insights could help make this app even better for everyone.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=da36bc6bb93c" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>