{"id":723,"date":"2021-01-11T15:41:58","date_gmt":"2021-01-11T23:41:58","guid":{"rendered":"https:\/\/www.ibabbleon.com\/copywriter-translator\/?p=723"},"modified":"2021-06-28T15:45:49","modified_gmt":"2021-06-28T22:45:49","slug":"how-to-localize-swiftui-elements-in-xcode-12-nslocalizedstring","status":"publish","type":"post","link":"https:\/\/www.ibabbleon.com\/copywriter-translator\/2021\/01\/how-to-localize-swiftui-elements-in-xcode-12-nslocalizedstring\/","title":{"rendered":"How to localize SwiftUI elements in Xcode 12"},"content":{"rendered":"\n<blockquote class=\"wp-block-quote\"><p><span class=\"has-inline-color has-vivid-green-cyan-color\">Update: It got easier! See our complete <a href=\"https:\/\/www.ibabbleon.com\/swiftui_localization_tutorial.html\">SwiftUI localization tutorial<\/a> here with Xcode 13<\/span><\/p><\/blockquote>\n\n\n\n<h2 id=\"swiftui-localization\">SwiftUI localization is easy\u2026 right?<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote\"><p><em>TL;DR Using NSLocalizedString() is still the best way to localize in SwiftUI.<\/em><\/p><\/blockquote>\n\n\n\n<p>Sometimes Apple gets localization so right that it &#8220;just works&#8221;. At first glance, SwiftUI localization in Xcode seems like that. For example, look at this simple SwiftUI localization example:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><strong>import<\/strong> SwiftUI<\/pre>\n\n\n\n<p><strong>struct<\/strong> <span class=\"has-inline-color has-vivid-cyan-blue-color\">ContentView<\/span>: <span class=\"has-inline-color has-vivid-purple-color\">View<\/span> {<br \/>&nbsp; &nbsp; <strong>var<\/strong> <span class=\"has-inline-color has-vivid-cyan-blue-color\">body<\/span>: <strong>some<\/strong> <span class=\"has-inline-color has-vivid-purple-color\">View<\/span> {<br \/>            <span class=\"has-inline-color has-vivid-purple-color\">Text<\/span>(<span class=\"has-inline-color has-vivid-red-color\">&#8220;SwiftUI Localization Tutorial&#8221;<\/span>)<br \/>    }<br \/>}<\/p>\n\n\n\n<p>Did you notice any special localization code for SwiftUI yet? <strong>There was none. <\/strong>Because in Xcode 12, SwiftUI automatically includes literal text inside of <span class=\"has-inline-color has-vivid-purple-color\">Text()<\/span> labels in all localization files. Just select <strong>Editor -&gt; Export for localization\u2026<\/strong> and the text <span class=\"has-inline-color has-vivid-red-color\">&#8220;SwiftUI Localization Tutorial&#8221;<\/span> will be included for your translators.<\/p>\n\n\n\n<p>You can even turn off this automatic localization in SwiftUI using the verbatim initializer:<\/p>\n\n\n\n<p><span class=\"has-inline-color has-vivid-purple-color\">Text<\/span>(verbatim: <span class=\"has-inline-color has-vivid-red-color\">&#8220;SwiftUI Localization Tutorial&#8221;<\/span>) <\/p>\n\n\n\n<p>This text will be displayed in English no matter which language the user chooses. (This is a good way of leaving untranslatable elements, like your app name, out of the Xcode localization export.)<\/p>\n\n\n\n<h2>SwiftUI localization is incomplete<\/h2>\n\n\n\n<p>That&#8217;s the end of &#8220;easy&#8221; though. Most developers get confused as soon as they pass a variable to the <span class=\"has-inline-color has-vivid-purple-color\">Text()<\/span> label, however:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-vivid-green-cyan-color\">var<\/span> <span class=\"has-inline-color has-vivid-cyan-blue-color\">label<\/span>:<span class=\"has-inline-color has-vivid-purple-color\">String<\/span>\n<span class=\"has-inline-color has-vivid-purple-color\">Text<\/span>(label)<\/code><\/pre>\n\n\n\n<p>This won&#8217;t get localized. <strong>Xcode assumes by default that variables should not be localized.<\/strong> This is explained in the <a href=\"https:\/\/developer.apple.com\/documentation\/swiftui\/text\">SwiftUI documentation<\/a> from Apple. One way around this is to explicitly convert the text to a localized string key:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><code><span class=\"has-inline-color has-vivid-purple-color\">Text<\/span>(<span class=\"has-inline-color has-vivid-purple-color\">LocalizedStringKey<\/span>(label))<\/code><\/pre>\n\n\n\n<p>If you use <span class=\"has-inline-color has-vivid-purple-color\">LocalizedStringKey<\/span>, Xcode does look for a localized string to replace the variable. But\u2014and it&#8217;s a <em>big<\/em> but\u2014the text won&#8217;t get exported for localization automatically. You must add it manually to a <span class=\"has-inline-color has-vivid-red-color\">Localizable.strings<\/span> file at the top of your project hierarchy.<\/p>\n\n\n\n<p>There are other types of hard-coded strings that must ALSO be localized into every language. For instance, text inside a <span class=\"has-inline-color has-vivid-purple-color\">Button()<\/span> call or <span class=\"has-inline-color has-vivid-purple-color\">navigationTitle<\/span>().<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><span class=\"has-inline-color has-vivid-purple-color\">Button<\/span>(<span class=\"has-inline-color has-vivid-red-color\">\"Go to Localization Tutorial\"<\/span>, action: goTutorial)<\/pre>\n\n\n\n<p>Text inside of <span class=\"has-inline-color has-vivid-purple-color\">Button()<\/span> labels need to be localized, just like the text blocks in previous examples. But localizing buttons doesn&#8217;t come &#8220;for free&#8221; with SwiftUI Localization. Why? I have no idea, but hope it will be rectified in future Xcode and SwiftUI localization updates. <\/p>\n\n\n\n<h2 id=\"swiftui-localization-nslocalizedstring\">SwiftUI localization using NSLocalizedString<\/h2>\n\n\n\n<p>The easiest way to localize all hard-coded strings in SwiftUI is the same way we localize text in Swift generally. Use the <span class=\"has-inline-color has-vivid-purple-color\">NSLocalizedString()<\/span> macro:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><span class=\"has-inline-color has-vivid-purple-color\">Button<\/span>(<span class=\"has-inline-color has-vivid-purple-color\">NSLocalizedString<\/span>(<span class=\"has-inline-color has-vivid-red-color\">\"go.button\"<\/span>, value:<span class=\"has-inline-color has-vivid-red-color\">\"Go to Localization Tutorial\"<\/span>, comment:<span class=\"has-inline-color has-vivid-red-color\">\"Takes user to the tutorial page\"<\/span>), action: goTutorial)<\/pre>\n\n\n\n<p>The <span class=\"has-inline-color has-vivid-purple-color\">NSLocalizedString()<\/span> macro lets you choose a unique key for the text, include the default (English) value, as well as add a comment for the translator. <strong>These texts inside NSLocalizedString will be exported into your localization files! <\/strong>For a full tutorial check out:<\/p>\n\n\n\n<p><a href=\"https:\/\/www.ibabbleon.com\/iphone_app_localization.html\">iOS Localization Tutorial<\/a><\/p>\n\n\n\n<p><strong>One last note about comments:<\/strong> <em>Comments are important<\/em> because your translator might not be able to &#8220;see&#8221; the text in context. Telling a translator the text is a button helps a lot. A headline, for example, might be translated differently in many languages.<\/p>\n\n\n\n<p><strong>Further reading:<\/strong><\/p>\n\n\n\n<p><a href=\"https:\/\/www.ibabbleon.com\/swiftui_localization_tutorial.html\">SwiftUI Localization Tutorial<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Update: It got easier! See our complete SwiftUI localization tutorial here with Xcode 13 SwiftUI localization is easy\u2026 right? TL;DR Using NSLocalizedString() is still the best way to localize in ","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"sfsi_plus_gutenberg_text_before_share":"","sfsi_plus_gutenberg_show_text_before_share":"","sfsi_plus_gutenberg_icon_type":"","sfsi_plus_gutenberg_icon_alignemt":"","sfsi_plus_gutenburg_max_per_row":""},"categories":[5],"tags":[68,80,91,90,89,65],"_links":{"self":[{"href":"https:\/\/www.ibabbleon.com\/copywriter-translator\/wp-json\/wp\/v2\/posts\/723"}],"collection":[{"href":"https:\/\/www.ibabbleon.com\/copywriter-translator\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ibabbleon.com\/copywriter-translator\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ibabbleon.com\/copywriter-translator\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ibabbleon.com\/copywriter-translator\/wp-json\/wp\/v2\/comments?post=723"}],"version-history":[{"count":6,"href":"https:\/\/www.ibabbleon.com\/copywriter-translator\/wp-json\/wp\/v2\/posts\/723\/revisions"}],"predecessor-version":[{"id":783,"href":"https:\/\/www.ibabbleon.com\/copywriter-translator\/wp-json\/wp\/v2\/posts\/723\/revisions\/783"}],"wp:attachment":[{"href":"https:\/\/www.ibabbleon.com\/copywriter-translator\/wp-json\/wp\/v2\/media?parent=723"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ibabbleon.com\/copywriter-translator\/wp-json\/wp\/v2\/categories?post=723"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ibabbleon.com\/copywriter-translator\/wp-json\/wp\/v2\/tags?post=723"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}