<?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: Hugo Bernardo Cardoso</title>
    <description>The latest articles on DEV Community by Hugo Bernardo Cardoso (@hugo_bernardocardoso_d38).</description>
    <link>https://dev.to/hugo_bernardocardoso_d38</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4050021%2F0e7bcfb6-0269-4390-8e3e-5f84b22192b5.jpg</url>
      <title>DEV Community: Hugo Bernardo Cardoso</title>
      <link>https://dev.to/hugo_bernardocardoso_d38</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hugo_bernardocardoso_d38"/>
    <language>en</language>
    <item>
      <title>How to Translate Game Localization Files (.JSON / .PO) Without Breaking Code Variables</title>
      <dc:creator>Hugo Bernardo Cardoso</dc:creator>
      <pubDate>Mon, 27 Jul 2026 18:38:44 +0000</pubDate>
      <link>https://dev.to/hugo_bernardocardoso_d38/how-to-translate-game-localization-files-json-po-without-breaking-code-variables-2334</link>
      <guid>https://dev.to/hugo_bernardocardoso_d38/how-to-translate-game-localization-files-json-po-without-breaking-code-variables-2334</guid>
      <description>&lt;p&gt;Introduction: The Scale vs. Code Integrity Dilemma&lt;br&gt;
Localizing an indie game or a software product is no longer optional. On platforms like Steam, offering the standard 28-language catalogue (including Simplified Chinese, Japanese, Korean, German, and Brazilian Portuguese) routinely unlocks over 50% of a game's total revenue potential.&lt;br&gt;
Yet, indie game developers face a brutal trade-off:&lt;br&gt;
Human Translation Agencies: Charging $\$0.10$ to $\$0.20$ per word. Localizing a modest 20,000-word game into 28 languages can easily cost $\$30,000+$, completely pricing out solo developers and small teams.&lt;br&gt;
Traditional Enterprise SaaS (Lokalise, Crowdin): Charging $\$50$ to $\$200+$ per month just for workspace access, forcing developers into bloated workflows and complex account setups.&lt;br&gt;
Naïve Single-Pass AI (Raw ChatGPT/Claude): Fast and cheap, but destructive to game builds.&lt;/p&gt;

&lt;p&gt;This article explores the technical breakdown of why standard LLMs fail when processing code files, and details the engineering architecture required to build a code-safe, zero-friction localization pipeline.&lt;br&gt;
Section 1: Anatomy of a Build Crash - Why Raw LLMs Corrupt&amp;nbsp;Code&lt;br&gt;
Large Language Models (LLMs) are statistical text predictors designed for natural human prose. They lack an internal compiler or Abstract Syntax Tree (AST) context when reading a raw file.&lt;br&gt;
When you paste a&amp;nbsp;.json,&amp;nbsp;.po,&amp;nbsp;.yaml, or&amp;nbsp;.csv file into a standard LLM, five distinct failure modes occur:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Variable &amp;amp; Token&amp;nbsp;Mutation
Game engines rely on runtime string interpolation. When an LLM encounters:
JSON
"hud_gold": "You collected {gold_amount} coins from {monster_type}."
It frequently translates the variable names inside the brackets:
JSON
"hud_gold": "Você coletou {quantidade_ouro} moedas de {tipo_monstro}." // ❌ CRASH: Engine looks for {gold_amount}&lt;/li&gt;
&lt;li&gt;Positional &amp;amp; Printf Specifier Mangling
C-style formatting specifiers like %s, %d, %f, or&amp;nbsp;:user are often dropped, reordered without positional indexes, or spaced out:
JSON
"save_slot": "Save file %s loaded." -&amp;gt; "Save file % s loaded." // ❌ PARSE ERROR&lt;/li&gt;
&lt;li&gt;ICU Plural Rule Destruction
Complex game strings use ICU plural syntax to handle numerical agreement:
Plaintext
{count, plural, =0 {No items} =1 {One item} other {# items}}
Standard LLMs frequently translate the structural control keywords (plural, other), breaking the engine's localization parser entirely.&lt;/li&gt;
&lt;li&gt;Rich Text &amp;amp; HTML Tag Pollution
Game engines (like Unity's TextMeshPro or Godot's RichTextLabel) use inline markup like  or [b]. LLMs often translate color names (), drop closing tags, or convert angle brackets into unescaped HTML entities (&amp;lt;color&amp;gt;).&lt;/li&gt;
&lt;li&gt;Unescaped Quotes and Structural Syntax&amp;nbsp;Errors
In JSON or YAML files, if a translated French or Spanish string contains an unescaped double quote (e.g., "desc": "L'épée de l' "héros" "), the resulting output becomes invalid JSON, breaking the entire game build at boot.
Section 2: Architecture of an Engine-Aware Localization Engine
To guarantee zero build breaks, the translation process must be decoupled from the raw file structure. The LLM must never be allowed to touch raw code variables.
Here is the technical architecture behind LocaFile AI:
Plaintext
┌────────────────┐     ┌───────────────────────┐     ┌───────────────────────┐
│ Source File    │ ──&amp;gt; │ Engine Regex Parser   │ ──&amp;gt; │ Token Masking         │
│ (JSON/PO/CSV)  │     │ Auto-Detect Format    │     │ {var} ──&amp;gt; [[LOCK_0]]  │
└────────────────┘     └───────────────────────┘     └───────────────────────┘
                                                             │
┌────────────────┐     ┌───────────────────────┐                 ▼
│ Delivered ZIP  │ &amp;lt;── │ Post-Processing QA    │ &amp;lt;── ┌───────────────────────┐
│ (28 Languages) │     │ AST Validation &amp;amp; Fix  │     │ 3-Pass AI Engine      │
└────────────────┘     └───────────────────────┘     │ + Lore &amp;amp; Tone Rules   │
                                                 └───────────────────────┘
A. Engine Format Auto-Detection &amp;amp; AST&amp;nbsp;Parsing
The system supports 9 engine formats out of the box:
Godot:&amp;nbsp;.po, Godot&amp;nbsp;.csv (multi-column
Unity: Unity&amp;nbsp;.csv, i18n&amp;nbsp;.json
Unreal &amp;amp; Mobile: XLIFF, iOS&amp;nbsp;.strings, Android&amp;nbsp;.xml
Web Frameworks:&amp;nbsp;.yaml,&amp;nbsp;.tsv, Laravel PHP lang arrays&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An AST parser extracts translatable values while maintaining the exact key mapping, structural nested hierarchy, and array index positions.&lt;br&gt;
B. The Immutable Variable&amp;nbsp;Locker&lt;br&gt;
Before any prompt is constructed, a multi-stage Regex scanner identifies all control variables, HTML/rich-text tags, positional specifiers, and ICU blocks:&lt;br&gt;
Detection: Identifies patterns matching {...}, %s, %d,&amp;nbsp;:key, , [tag], and indexed placeholders {0}.&lt;br&gt;
Replacement: Replaces each detected variable with an immutable, deterministic lock token: [[LOCK_0]], [[LOCK_1]], etc.&lt;br&gt;
Why Double Square Brackets? Double square bracket tokens ([[LOCK_N]]) do not naturally occur in legitimate game dialogue or software strings. They prevent LLM tokenization distortion and survive the AI translation pass untouched.&lt;/p&gt;

&lt;p&gt;C. Lore Glossaries &amp;amp; Prompt Injection Protection&lt;br&gt;
Game lore uses proper nouns (character names, fictional planets, unique spells) that must remain identical across all languages.&lt;br&gt;
Lore Glossary Engine: Developers can pass up to 2,000 characters of proper nouns (e.g., "CyberCore, Eldoria, X-400").&lt;br&gt;
Security: Glossaries are validated against strict prompt-injection detection patterns before being appended as immutable system constraints.&lt;/p&gt;

&lt;p&gt;D. Context &amp;amp; Tone Customization&lt;br&gt;
Language register heavily impacts player immersion. A medieval RPG demands formal or archaic phrasing, while a modern shooter requires punchy, casual dialogue.&lt;br&gt;
Developers can specify target registers:&lt;br&gt;
Standard: Clean, neutral UI phrasing.&lt;br&gt;
Casual: Natural, conversational registers (e.g., informal "tu" in French/Spanish).&lt;br&gt;
Fantasy / Heroic: Immersive register for RPGs and story-driven titles.&lt;br&gt;
Sci-Fi / Cyberpunk: Stylized technical phrasing.&lt;/p&gt;

&lt;p&gt;Section 3: The Automated Post-Processing QA &amp;amp; Auto-Fix&amp;nbsp;Pipeline&lt;br&gt;
Even with prompt constraints, an production-grade system cannot rely solely on the LLM's output. A dedicated post-processing engine must validate every single key before packaging.&lt;/p&gt;


&lt;ol&gt;

&lt;li&gt;&lt;p&gt;Linguistic Variable Checker (Regex AST Validator)&lt;br&gt;&lt;br&gt;
Before delivering the final ZIP bundle, a dedicated post-processing engine compares the source string against the target translation across 5 variable patterns:&lt;br&gt;&lt;br&gt;
Curly Brackets: {player_name}&lt;br&gt;&lt;br&gt;
Colon Specifiers:&amp;nbsp;:attribute&lt;br&gt;&lt;br&gt;
Printf Tokens: %s, %d&lt;br&gt;&lt;br&gt;
Markup Tags: , &lt;b&gt;&lt;br&gt;&lt;br&gt;
Indexed Tokens: {0}, {1}&lt;/b&gt;&lt;/p&gt;&lt;/li&gt;
&lt;b&gt;&lt;br&gt;
&lt;li&gt;&lt;p&gt;Defect Detection &amp;amp; Auto-Fix&amp;nbsp;Engine&lt;br&gt;&lt;br&gt;
The QA validator flags three types of issues:&lt;br&gt;&lt;br&gt;
Missing Variables: The source string had {count}, but the translation dropped it.&lt;br&gt;&lt;br&gt;
Corrupted Variables: The AI altered the internal token (e.g., [[LOCK_0]] became [[LOCK_0_ES]]).&lt;br&gt;&lt;br&gt;
Extra Variables: Unsanitized tokens present in translation but absent in source.&lt;/p&gt;&lt;/li&gt;
&lt;br&gt;
&lt;/b&gt;
&lt;/ol&gt;
&lt;b&gt;

&lt;/b&gt;&lt;p&gt;Automated Re-Injection: When a missing variable is detected, the engine calculates its semantic position relative to surrounding words and automatically re-injects the missing {variable} into the translated string before generating a detailed report (quality-report.json).&lt;br&gt;
Section 4: Pay-Per-Pass vs. Monthly Subscriptions&lt;br&gt;
The SaaS industry is saturated with recurring monthly subscriptions that penalize developers during idle development phases. Indie game development is inherently bursty: you might localize heavily during a major launch or playtest, and then go months without needing translation updates.&lt;br&gt;
Why Pay-Per-Pass Wins for Indie Game&amp;nbsp;Devs:&lt;br&gt;
PRICING COMPARISON:&lt;br&gt;
Human Agencies&amp;nbsp;: $0.10 - $0.20/word | High Cost | Manual Variable Handling&lt;br&gt;
Enterprise SaaS&amp;nbsp;: $50 - $200+/month | Subscription| Complex Workspace Setup&lt;br&gt;
LocaFile AI&amp;nbsp;: From $19 (Flat) | Pay-per-Pass| Automated Variable Protection&lt;br&gt;
Indie Starter ($19): 3 runs, up to 5,000 words/file across 6 core languages (EFIGS + CJK).&lt;br&gt;
Steam Launchpad ($99): 10 runs, up to 25,000 words/file across all 28 Steam catalogue languages.&lt;br&gt;
Studio Pass ($249): 35 runs, up to 100,000 words/file for large-scale RPGs and studio pipelines.&lt;/p&gt;

&lt;p&gt;Section 5: Hands-On Tutorial - Localizing a Game in 3&amp;nbsp;Steps&lt;br&gt;
Step 1: Prepare Your Game&amp;nbsp;File&lt;br&gt;
Ensure your string keys are separated from translatable values in a supported format:&lt;br&gt;
JSON&lt;br&gt;
{&lt;br&gt;
  "quest_header": "Quest: Defeat {boss_name}",&lt;br&gt;
  "item_reward": "You earned {amount} gold coins!",&lt;br&gt;
  "dialogue_intro": "Welcome to Eldoria, traveler."&lt;br&gt;
}&lt;br&gt;
Step 2: Test Variable Protection (Zero-Cost Live&amp;nbsp;Preview)&lt;br&gt;
Navigate to locafileai.com and use the zero-cost Variable Protection Preview tool on the homepage.&lt;br&gt;
Paste your raw JSON snippet to observe the production VariableLocker instantly convert {boss_name} and  into protected [[LOCK_N]] tokens in real-time before initiating any pass.&lt;br&gt;
JSON&lt;br&gt;
// Real-time Variable Masking Output:&lt;br&gt;
{&lt;br&gt;
  "quest_header": "Quest: Defeat [[LOCK_0]]",&lt;br&gt;
  "item_reward": "You earned [[LOCK_1]][[LOCK_2]][[LOCK_3]] gold coins!",&lt;br&gt;
  "dialogue_intro": "Welcome to Eldoria, traveler."&lt;br&gt;
}&lt;br&gt;
Step 3: Run the Pass &amp;amp; Import to&amp;nbsp;Engine&lt;br&gt;
Drop File or ZIP Batch: Drag your&amp;nbsp;.json,&amp;nbsp;.po, or&amp;nbsp;.csv files directly onto the dropzone.&lt;br&gt;
Set Glossaries &amp;amp; Tone: Add proper nouns to your Lore Glossary and select your game's tone (e.g., Fantasy or Casual).&lt;br&gt;
Execute Pass: Select your target languages (or full 28 Steam catalogue) and watch live real-time WebSocket progress via Laravel Reverb.&lt;br&gt;
Export &amp;amp; Build: Download your validated ZIP bundle and drop it directly into your Godot res:// or Unity Assets/Resources/ directories. Zero syntax errors, zero build breaks.&lt;/p&gt;

&lt;p&gt;Conclusion&lt;br&gt;
Game localization should not require thousands of dollars in agency fees or hours spent debugging broken JSON brackets and mangled variable names. By isolating variables through pre-parsing AST Regex lockers, applying post-processing QA validation, and offering a fair pay-per-pass pricing model, developers can expand their games to a global Steam audience with total code safety.&lt;br&gt;
Test the real-time variable protection preview today at locafileai.com!&lt;/p&gt;



</description>
      <category>gamedev</category>
      <category>softwaredevelopment</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Localize a Godot Game Without Breaking Variable Tags</title>
      <dc:creator>Hugo Bernardo Cardoso</dc:creator>
      <pubDate>Mon, 27 Jul 2026 18:36:12 +0000</pubDate>
      <link>https://dev.to/hugo_bernardocardoso_d38/how-to-localize-a-godot-game-without-breaking-variable-tags-3gm8</link>
      <guid>https://dev.to/hugo_bernardocardoso_d38/how-to-localize-a-godot-game-without-breaking-variable-tags-3gm8</guid>
      <description>&lt;h1&gt;
  
  
  How to Localize a Godot Game Without Breaking Variable Tags
&lt;/h1&gt;

&lt;p&gt;Godot's localization system is built around a simple idea: separate your text from your code, translate the text, and let the engine swap it at runtime. In practice, the variable tags inside those strings are where things fall apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Godot handles translatable strings
&lt;/h2&gt;

&lt;p&gt;Godot, a &lt;a href="https://godotengine.org/features/" rel="noopener noreferrer"&gt;free, open-source game engine&lt;/a&gt; used by solo developers and small studios for 2D and 3D projects, stores translatable text in CSV files or .po (gettext) files. You define a key, write your source string, and add columns or entries for each target language.&lt;/p&gt;

&lt;p&gt;A typical CSV row might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csvs"&gt;&lt;code&gt;&lt;span class="k"&gt;QUEST&lt;/span&gt;&lt;span class="err"&gt;_&lt;/span&gt;&lt;span class="k"&gt;COMPLETE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"{player_name} finished the quest in {time} seconds"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in GDScript, you call it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"{player_name} finished the quest in {time} seconds"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="n"&gt;player_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;weapon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elapsed&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;Godot also supports C-style format strings (&lt;code&gt;%s&lt;/code&gt;, &lt;code&gt;%d&lt;/code&gt;) and rich text tags like &lt;code&gt;[color=red]&lt;/code&gt; in its RichTextLabel nodes. These are all over a typical game's translation file, and they all need to survive translation intact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where translations break
&lt;/h2&gt;

&lt;p&gt;The problem is not the translation itself. It is the variable tags inside the strings.&lt;/p&gt;

&lt;p&gt;When you paste &lt;code&gt;{player_name} picked up the {weapon}&lt;/code&gt; into a translation tool or general-purpose AI, several things can go wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Curly braces get translated.&lt;/strong&gt; Some tools interpret &lt;code&gt;{player_name}&lt;/code&gt; as natural language and translate "player" and "name" into the target language. Your code calls &lt;code&gt;.format()&lt;/code&gt; with the English key. It finds no match. The placeholder renders as raw text, or your game crashes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Format specifiers get reordered.&lt;/strong&gt; &lt;code&gt;%s killed %d enemies&lt;/code&gt; depends on argument order. A translator might flip the sentence structure for grammar but leave &lt;code&gt;%s&lt;/code&gt; and &lt;code&gt;%d&lt;/code&gt; in the original positions, swapping which value fills which slot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich text tags get mangled.&lt;/strong&gt; &lt;code&gt;[color=red]Warning[/color]&lt;/code&gt; might become &lt;code&gt;[couleur=rouge]Avertissement[/couleur]&lt;/code&gt; in French output, breaking BBCode parsing entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Whitespace around tags disappears.&lt;/strong&gt; Tokenizers strip or merge spaces near braces and brackets, producing &lt;code&gt;{player_name}picked up&lt;/code&gt; with no space between the variable and the next word.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These bugs are silent. The CSV file looks fine. The game launches. Then a Japanese player sees &lt;code&gt;{player_name}&lt;/code&gt; rendered as literal text on screen because the translator converted the curly braces to full-width characters.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to protect your tags
&lt;/h2&gt;

&lt;p&gt;The reliable approach is to replace every variable tag with a placeholder token before translation, then restore the originals after.&lt;/p&gt;

&lt;p&gt;Here is the process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scan each string for variable patterns.&lt;/strong&gt; Match &lt;code&gt;{...}&lt;/code&gt;, &lt;code&gt;%s&lt;/code&gt;, &lt;code&gt;%d&lt;/code&gt;, &lt;code&gt;%f&lt;/code&gt;, &lt;code&gt;[color=...]...[/color]&lt;/code&gt;, and any custom tags your project uses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replace each match with a numbered token&lt;/strong&gt; like &lt;code&gt;__VAR_0__&lt;/code&gt;, &lt;code&gt;__VAR_1__&lt;/code&gt;. Store the mapping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send only the tokenized string to translation.&lt;/strong&gt; The translator (human or AI) sees plain text with inert tokens it has no reason to modify.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After translation, swap the tokens back&lt;/strong&gt; to the original variable tags, byte for byte.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is the approach &lt;a href="//www.locafileai.com"&gt;LocaFile AI&lt;/a&gt; uses. When you upload a Godot CSV or .po file, it detects and locks every variable pattern, including &lt;code&gt;{player_name}&lt;/code&gt;, &lt;code&gt;%s&lt;/code&gt;, &lt;code&gt;%d&lt;/code&gt;, and &lt;code&gt;&amp;lt;color=red&amp;gt;&lt;/code&gt; tags, with regex-based token replacement before the AI model sees the string. After translation, the original tags are restored exactly. The AI only ever processes plain text with inert placeholders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical checks before you ship
&lt;/h2&gt;

&lt;p&gt;Even with tags protected, verify your translations before release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Test with pseudolocalization.&lt;/strong&gt; Godot has a built-in pseudolocalization mode (Project Settings &amp;gt; Internationalization &amp;gt; Locale) that replaces your strings with accented, elongated versions. It catches hardcoded strings you forgot to externalize and UI elements that overflow with longer text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check font coverage.&lt;/strong&gt; Godot's default font only covers Latin-1 characters. For CJK, Cyrillic, Arabic, or Thai, load a font like Noto Sans as a DynamicFont resource and set it as your theme's default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle pluralization properly.&lt;/strong&gt; English has two plural forms. Polish has four. Arabic has six. Godot's &lt;code&gt;tr_n()&lt;/code&gt; function handles this per-locale, but your source strings need to be structured for it: &lt;code&gt;tr_n("There is %d apple", "There are %d apples", count)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test RTL languages.&lt;/strong&gt; If you are shipping in Arabic or Hebrew, Godot automatically mirrors UI anchors, margins, and control order. But icons with directional arrows (back/forward buttons) need manual attention.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The real cost of skipping localization
&lt;/h2&gt;

&lt;p&gt;Steam's audience is global. Roughly 60% of Steam users have their client set to a non-English language. Shipping English-only means your store page, your reviews, and your in-game text are invisible to most of the platform.&lt;/p&gt;

&lt;p&gt;The traditional path, hiring an agency, costs thousands of dollars per language and takes weeks. The shortcut of running your CSV through ChatGPT produces translations that look correct until &lt;code&gt;{player_name}&lt;/code&gt; shows up as literal text on a player's screen.&lt;/p&gt;

&lt;p&gt;Variable-safe translation closes that gap. Protect the tags, translate the text, verify with pseudolocalization, ship.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>programming</category>
      <category>software</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
