<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Pokémon Following Renegade Platinum on Christian Martínez De La Rosa</title><link>https://christt105.github.io/categories/pok%C3%A9mon-following-renegade-platinum/</link><description>Recent content in Pokémon Following Renegade Platinum on Christian Martínez De La Rosa</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Sun, 30 Aug 2026 00:00:00 +0200</lastBuildDate><atom:link href="https://christt105.github.io/categories/pok%C3%A9mon-following-renegade-platinum/index.xml" rel="self" type="application/rss+xml"/><item><title>How I Translated Pokémon Following Renegade Platinum</title><link>https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/</link><pubDate>Sun, 30 Aug 2026 00:00:00 +0200</pubDate><guid>https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/</guid><enclosure url="https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/cover.webp" length="61886" type="image/webp"/><description>&lt;p&gt;Let&amp;rsquo;s bring back a project from several years ago that I&amp;rsquo;m quite proud of.&lt;/p&gt;&#10;&lt;h2 id="how-it-all-started"&gt;How it all started&#10;&lt;/h2&gt;&lt;p&gt;I felt like playing the fourth generation of Pokémon, but I wanted something different, with quality-of-life mechanics. While looking into it I found Pokémon Renegade Platinum, a Pokémon Platinum hack with more difficulty and lots of improvements, made by Drayano. I also found a project by two Spaniards, Mikelan98 and AdAstra, called Pokémon Following Platinum, a Pokémon Platinum hack that added the characteristic Pokémon HeartGold and SoulSilver mechanic of Pokémon following you around the overworld. It also added a few improvements, like the Fairy type and a bit more. Finally, there was someone who had merged both patches into one that included the following Pokémon in Renegade Platinum. That&amp;rsquo;s what I wanted. There was a problem: it was in English, and I really didn&amp;rsquo;t feel like playing it with the moves in English.&lt;/p&gt;&#10;&lt;p&gt;Pokémon Renegade Platinum was translated by Drakyem, who did an excellent job. On the other hand, even though the people behind Pokémon Following Platinum are Spanish, they only released it in English. So I set out to translate Following Platinum and then combine both translations into Pokémon Following Renegade Platinum, with no idea where to start.&lt;/p&gt;&#10;&lt;p&gt;I found a fairly old, obscure program that exported all the dialogue from a ROM. You could then edit it and load it back into the game. Workflow sorted, I could get started. My idea was simple: extract the dialogue from an English and a Spanish Pokémon Platinum ROM, match up all the dialogue, extract the Following Platinum files and overwrite them with the ones from the original Spanish game, translate the few dialogue lines that Following Platinum added, and finally take the Spanish Renegade Platinum lines, overwrite them into Following Renegade Platinum, and add the Following Platinum ones on top. That would give me a ROM with Drakyem&amp;rsquo;s translation and mine. Time to get to work.&lt;/p&gt;&#10;&lt;h2 id="the-translation-process"&gt;The translation process&#10;&lt;/h2&gt;&lt;p&gt;This is what I wanted to get to, with the dialogue already in Spanish and a Pokémon following me around the map:&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="Spanish dialogue with a Pokémon in the overworld during a cutscene in the lab" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="192" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/following-veamos.png" width="256"&gt;&lt;/p&gt;&#10;&lt;p&gt;Before anything else, I had to build all the ROMs I&amp;rsquo;d need: Pokémon Platinum in English and Spanish, Pokémon Renegade Platinum in English and Spanish (patched with Drayano&amp;rsquo;s hack), and Pokémon Following Platinum, which only existed in English, so I made a copy to work on in Spanish. All of this with thenewpoketext, the tool that exports and imports text from Nintendo DS Pokémon ROMs. I wrote a Python script for each step of the process, so let me walk through what each one did.&lt;/p&gt;&#10;&lt;p&gt;With so many ROMs and scripts moving around at once, here&amp;rsquo;s how the whole process fit together:&lt;/p&gt;&#10;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD&#10; A["Platinum EN + ES&lt;br/&gt;Renegade EN + ES&lt;br/&gt;Following EN"] --&gt;|export.py| B["XML for&lt;br/&gt;each ROM"]&#10; B --&gt;|comparer.py| C["EN↔ES diffs&lt;br/&gt;per pair"]&#10; C --&gt;|replace.py| D["Following ES&lt;br/&gt;(text recycled&lt;br/&gt;from Platinum)"]&#10; D --&gt;|"translate_following.py&lt;br/&gt;+ manual review"| E["Following ES&lt;br/&gt;(translated)"]&#10; E --&gt;|"import_following_into_&lt;br/&gt;followingrenegade.py"| F["Following&lt;br/&gt;Renegade ES"]&#10; C --&gt;|"Renegade ES&lt;br/&gt;(Drakyem)"| F&#10; F --&gt;|"thenewpoketext:&lt;br/&gt;patch + mkrom"| G["Playable ROMs&lt;br/&gt;in Spanish"]&lt;/pre&gt;&lt;h3 id="exporting-and-comparing-the-dialogue"&gt;Exporting and comparing the dialogue&#10;&lt;/h3&gt;&lt;p&gt;The first step was pulling the text out of the ROMs. &lt;code&gt;export.py&lt;/code&gt; called thenewpoketext to dump each ROM&amp;rsquo;s dialogue into an XML file, and along the way used &lt;code&gt;msg_name_changer.py&lt;/code&gt; to rename a couple of message &lt;code&gt;.narc&lt;/code&gt; files that come out misordered in Platinum unless you fix them by hand. Finding that out in the first place took me a while.&lt;/p&gt;&#10;&lt;p&gt;With everything in XML, &lt;code&gt;comparer.py&lt;/code&gt; came in. This script took pairs of ROMs (English Platinum vs. Spanish Platinum, English Renegade vs. Spanish Renegade, English Following vs. English Following Renegade, etc.) and, relying on &lt;code&gt;xml_parser.py&lt;/code&gt; to read each XML into a dictionary, compared dialogue line by line by id. It saved the result in two JSON formats: one with all the changes together, and another split into three blocks — text that changes between the two ROMs, text missing from the first, and text missing from the second. This comparison is the backbone of the whole project: it let me know exactly which English line matched which Spanish line, and which lines were new and didn&amp;rsquo;t exist in the original game.&lt;/p&gt;&#10;&lt;p&gt;This is, roughly, the part that splits things into those three blocks:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;span class="lnt"&gt;25&#10;&lt;/span&gt;&lt;span class="lnt"&gt;26&#10;&lt;/span&gt;&lt;span class="lnt"&gt;27&#10;&lt;/span&gt;&lt;span class="lnt"&gt;28&#10;&lt;/span&gt;&lt;span class="lnt"&gt;29&#10;&lt;/span&gt;&lt;span class="lnt"&gt;30&#10;&lt;/span&gt;&lt;span class="lnt"&gt;31&#10;&lt;/span&gt;&lt;span class="lnt"&gt;32&#10;&lt;/span&gt;&lt;span class="lnt"&gt;33&#10;&lt;/span&gt;&lt;span class="lnt"&gt;34&#10;&lt;/span&gt;&lt;span class="lnt"&gt;35&#10;&lt;/span&gt;&lt;span class="lnt"&gt;36&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compare_files_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;files_dict1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;files_dict2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;changed&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;missing_in_1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;missing_in_2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;texts_dict1&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;files_dict1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;file_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;files_dict2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;text_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text1&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;texts_dict1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;missing_in_2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})[&lt;/span&gt;&lt;span class="n"&gt;text_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;text1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;text2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;texts_dict2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;files_dict2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;text_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text1&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;texts_dict1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;text_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;texts_dict2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;missing_in_2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})[&lt;/span&gt;&lt;span class="n"&gt;text_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;text1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;text2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;text2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;texts_dict2&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;text_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;text1&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;text2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;changed&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})[&lt;/span&gt;&lt;span class="n"&gt;text_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;text1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;text2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# ... and the same loop in reverse to fill in &amp;#34;missing_in_1&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;I also wrote a couple of support scripts to eyeball all of this: &lt;code&gt;export_csv.py&lt;/code&gt;, which dumps every XML into a single CSV table with one column per ROM so I could compare things quickly, and &lt;code&gt;check_max_newline.py&lt;/code&gt;, which goes through the original dialogue to work out how many characters fit on a line of the text box before the game inserts an automatic line break.&lt;/p&gt;&#10;&lt;h3 id="reusing-the-pokémon-platinum-translation"&gt;Reusing the Pokémon Platinum translation&#10;&lt;/h3&gt;&lt;p&gt;With the comparison done, &lt;code&gt;replace.py&lt;/code&gt; took the English text from Following Platinum and Following Renegade Platinum and, wherever it matched a line from the original Platinum or Renegade Platinum, swapped it for the Spanish equivalent. The result was a ROM almost entirely in Spanish, except for the new dialogue that Mikelan98 and AdAstra had written for Following Platinum, which didn&amp;rsquo;t exist in the original game and so had no translation to match against.&lt;/p&gt;&#10;&lt;h3 id="translating-the-new-following-platinum-content"&gt;Translating the new Following Platinum content&#10;&lt;/h3&gt;&lt;p&gt;Those new lines were almost all concentrated in a single file, 724. I don&amp;rsquo;t remember whether an AI like ChatGPT already existed at the time — I imagine it did, but nowhere near today&amp;rsquo;s level — so all of this was pretty handmade. My idea from the start was to write the scripts needed to translate both ROMs without having to do everything by hand, so I fell back on good old machine translation: &lt;code&gt;translate_following.py&lt;/code&gt; went through that file with the &lt;code&gt;deep_translator&lt;/code&gt; library, which is just a Python wrapper around translators like Google Translate or MyMemory, and produced a CSV with the original text and its translation. Before sending each line off to be translated I had to swap out variables like the player&amp;rsquo;s name or a Pokémon&amp;rsquo;s name for placeholder text, otherwise the translator would eat or mangle those tags.&lt;/p&gt;&#10;&lt;p&gt;This is roughly what the resulting CSV looked like, with the dialogue id inside file 724, the original text, and the machine translation (line 5 is, in fact, the same line that shows up in one of the screenshots further down):&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csv" data-lang="csv"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;id;original;translated&lt;/span&gt;&lt;span class="p"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;2;......\nYour Pokémon won’t look you in the eye.;...... Tu Pokémon no te mira a los ojos.&lt;/span&gt;&lt;span class="p"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;5;...Your Pokémon is so very angry!;... ¡Tu Pokémon está muy enfadado!&lt;/span&gt;&lt;span class="p"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;20;Your Pokémon is dancing with you!;¡Tu Pokémon está bailando contigo!&lt;/span&gt;&lt;span class="p"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;I went through that CSV entry by entry by hand to polish the machine translation, which got things wrong quite a bit for short video game lines. &lt;code&gt;import_translation_following.py&lt;/code&gt; fed that reviewed CSV back into the XML, undoing the variable placeholders, trimming lines that were too long to fit the text box, and hand-translating a handful of texts that fell outside file 724 and weren&amp;rsquo;t worth automating.&lt;/p&gt;&#10;&lt;h3 id="merging-following-platinum-with-renegade-platinum"&gt;Merging Following Platinum with Renegade Platinum&#10;&lt;/h3&gt;&lt;p&gt;With Following Platinum translated, I moved on to Following Renegade Platinum. There was nothing new to translate here: Renegade Platinum&amp;rsquo;s dialogue was already translated by Drakyem, and Following Platinum&amp;rsquo;s had just been translated by me — I just had to merge them. &lt;code&gt;import_following_into_followingrenegade.py&lt;/code&gt; used the comparison between English Renegade Platinum and English Following Platinum to know exactly which lines the latter added, and for each of them copied the already-done translation from the Spanish Following Platinum XML into the Spanish Following Renegade Platinum XML. The result was the complete Following Renegade Platinum XML in Spanish.&lt;/p&gt;&#10;&lt;h3 id="putting-it-all-back-into-the-rom"&gt;Putting it all back into the ROM&#10;&lt;/h3&gt;&lt;p&gt;The last step, for all three ROMs, was loading the translated XML back into the game with thenewpoketext, patching the ROM and reordering those message &lt;code&gt;.narc&lt;/code&gt; files again. That gave me playable ROMs in Spanish. Along the way I ran into the odd curious bug, like a broken Regigigas dialogue line, which I also fixed and documented in the repository itself.&lt;/p&gt;&#10;&lt;p&gt;A few things were left untranslated, like text baked into images rather than dialogue — the names of Pokémon types on some screen, for example — but those are minor details that don&amp;rsquo;t get in the way of playing the game in Spanish.&lt;/p&gt;&#10;&lt;p&gt;Looking at the commits, it didn&amp;rsquo;t actually take that long. The first one is from February 19, 2023, I published the Following Platinum patch on March 13, and Following Renegade Platinum arrived just three days later, on March 16, since the translation was already done and it just needed merging. It wasn&amp;rsquo;t three straight weeks of working on it every day — there were gaps of several days between commits — but for how handmade the process was, it came together pretty fast.&lt;/p&gt;&#10;&lt;a class="github-repo-card" href="https://github.com/christt105/PokemonFollowingRenegadePlatinumTranslation" target="_blank" rel="noopener"&gt;&#10; &lt;img src="https://avatars.githubusercontent.com/u/36189169?v=4" alt="christt105 avatar" class="repo-avatar"&gt;&#10; &lt;h3&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-github" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"&gt;&#10; &lt;path stroke="none" d="M0 0h24v24H0z" fill="none"/&gt;&#10; &lt;path d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5" /&gt;&#10;&lt;/svg&gt;&#10;&#10;&#10; christt105/PokemonFollowingRenegadePlatinumTranslation&lt;/h3&gt;&#10; &lt;p&gt;&lt;/p&gt;&#10; &lt;div class="repo-stats"&gt;&#10; &lt;span&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" class="icon icon-tabler icons-tabler-filled icon-tabler-star"&gt;&lt;path stroke="none" d="M0 0h24v24H0z" fill="none"/&gt;&lt;path d="M8.243 7.34l-6.38 .925l-.113 .023a1 1 0 0 0 -.44 1.684l4.622 4.499l-1.09 6.355l-.013 .11a1 1 0 0 0 1.464 .944l5.706 -3l5.693 3l.1 .046a1 1 0 0 0 1.352 -1.1l-1.091 -6.355l4.624 -4.5l.078 -.085a1 1 0 0 0 -.633 -1.62l-6.38 -.926l-2.852 -5.78a1 1 0 0 0 -1.794 0l-2.853 5.78z" /&gt;&lt;/svg&gt; 3&lt;/span&gt;&#10; &lt;span&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-git-fork"&gt;&lt;path stroke="none" d="M0 0h24v24H0z" fill="none"/&gt;&lt;path d="M10 18a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /&gt;&lt;path d="M5 6a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /&gt;&lt;path d="M15 6a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" /&gt;&lt;path d="M7 8v2a2 2 0 0 0 2 2h6a2 2 0 0 0 2 -2v-2" /&gt;&lt;path d="M12 12l0 4" /&gt;&lt;/svg&gt; 0&lt;/span&gt;&#10; &lt;span&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-calendar-event"&gt;&lt;path stroke="none" d="M0 0h24v24H0z" fill="none"/&gt;&lt;path d="M4 7a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2l0 -12" /&gt;&lt;path d="M16 3l0 4" /&gt;&lt;path d="M8 3l0 4" /&gt;&lt;path d="M4 11l16 0" /&gt;&lt;path d="M8 15h2v2h-2l0 -2" /&gt;&lt;/svg&gt; 2026-05-12&lt;/span&gt;&#10; &lt;/div&gt;&#10; &lt;/a&gt;&#10;&lt;h2 id="classic-mode-and-shiny-odds"&gt;Classic Mode and shiny odds&#10;&lt;/h2&gt;&lt;p&gt;The repository didn&amp;rsquo;t stay still after 2023. Later on I added variants of the Following Renegade Platinum patch without touching anything in the translation process: &amp;ldquo;Classic&amp;rdquo; ones, which revert the type changes Drayano introduces in Renegade Platinum for anyone who prefers each Pokémon&amp;rsquo;s original types, and others that change the shiny encounter rate to 1/4096 or 1/512 instead of the base 1/8192, which can be combined with each other. Honestly, I haven&amp;rsquo;t been able to properly test the shiny rate change — I don&amp;rsquo;t have a reliable way to check the real odds without playing thousands of hours or brute-forcing it with an emulator, so I published it trusting the value change without being able to fully confirm it.&lt;/p&gt;&#10;&lt;h2 id="how-its-gone"&gt;How it&amp;rsquo;s gone&#10;&lt;/h2&gt;&lt;p&gt;More examples of the final result:&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="Spanish dialogue with another Pokémon following the protagonist in front of a house" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="192" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/following-enfadado.png" width="256"&gt;&#10;&lt;img alt="Spanish dialogue inside the protagonist’s house" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="192" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/following-laboratorio.png" width="256"&gt;&lt;/p&gt;&#10;&lt;p&gt;Counting only GitHub downloads, not the Google form or third-party sites it&amp;rsquo;s ended up on, the Following Platinum patch has more than 3700 downloads between the patch and the already-patched ROM, and Following Renegade Platinum has almost 2900 counting all its variants (normal, Classic Mode, and shiny). More than 6500 downloads between the two, for a project I made purely for myself.&lt;/p&gt;&#10;&lt;p&gt;I&amp;rsquo;m happy that so many people have enjoyed it, myself, my friends, and my sister included. It&amp;rsquo;s actually been downloaded by more people than those numbers show, since it&amp;rsquo;s ended up on third-party sites, some of which didn&amp;rsquo;t give credit. Xamork and Folagor both played it, though neither credited it and posted the direct download themselves. I played it and beat it with an all-Psychic team.&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="Pokémon Following Renegade Platinum Hall of Fame completed with an all-Psychic team" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="800" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/PokemonFollowingRenegadePlatinumMonotypeHallOfFame.png" srcset="https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/PokemonFollowingRenegadePlatinumMonotypeHallOfFame_hu_164864e17107a9b8.png 800w, https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/PokemonFollowingRenegadePlatinumMonotypeHallOfFame.png 1067w" width="1067"&gt;&lt;/p&gt;&#10;&lt;p&gt;I didn&amp;rsquo;t post a direct ROM download because it made me a bit nervous and I care a lot about my GitHub account. You can still download the patch from the repository or directly from &lt;a class="link" href="https://forms.gle/YwseURAufk9wccrJ9" target="_blank" rel="noopener"&#10; &gt;this form&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;I&amp;rsquo;ve really enjoyed making this and having other people enjoy it too. It&amp;rsquo;s a small contribution to the community of a franchise that meant so much to me growing up.&lt;/p&gt;&#10;&lt;p&gt;My sister 100%&amp;rsquo;d it, completing a Living Dex.&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="My sister’s complete Living Dex, with every Pokémon organized by Pokédex number" class="gallery-image" data-flex-basis="633px" data-flex-grow="263" height="1524" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/livingdex_collage.png" srcset="https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/livingdex_collage_hu_279ab6461f32449c.png 800w, https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/livingdex_collage_hu_52c3bef070ebf40c.png 1600w, https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/livingdex_collage_hu_752860622831a4f9.png 2400w, https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/livingdex_collage.png 4020w" width="4020"&gt;&#10;&lt;img alt="My sister’s trainer card" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="492" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/sister-trainer-card.png" width="656"&gt;&#10;&lt;img alt="Diploma for completing the National Pokédex" class="gallery-image" data-flex-basis="320px" data-flex-grow="133" height="492" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://christt105.github.io/blog/translating-pokemon-following-renegade-platinum/sister-diploma.png" width="656"&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;The trainer card says the adventure started in 2011, but that&amp;rsquo;s just because she never changed the console&amp;rsquo;s date — anyone who&amp;rsquo;s played Animal Crossing will understand.&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;And that&amp;rsquo;s today&amp;rsquo;s post. I&amp;rsquo;m really glad there&amp;rsquo;s people, besides me, enjoying what I make. See you next time!&lt;/p&gt;&#10;</description></item><item><title>Pokémon Following Renegade Platinum Translation</title><link>https://christt105.github.io/projects/pokemonfollowingrenegadeplatinum/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://christt105.github.io/projects/pokemonfollowingrenegadeplatinum/</guid><enclosure url="https://christt105.github.io/projects/pokemonfollowingrenegadeplatinum/PokemonFollowingPlatinum.webp" length="45500" type="image/webp"/><description>&lt;p&gt;This project provides translation patches for the ROM hacks Pokémon Following Platinum and Pokémon Following Renegade Platinum, making them fully playable in Spanish.&#10;It was developed using Python together with the tool thenewpoketext, which allows extraction, editing, and reinsertion of game text into the ROMs.&lt;/p&gt;&#10;&lt;p&gt;For Following Platinum, the translation combines the original Spanish text from Pokémon Platinum with newly translated content introduced by the hack.&#10;For Following Renegade Platinum, it builds upon Drakyem’s Spanish translation of Renegade Platinum, adding all the additional content from Following Platinum as well.&lt;/p&gt;&#10;</description></item></channel></rss>