AI-assisted software development for localization
Introduction
Customers have asked us for localized versions of JDisc Discovery for quite some time—especially in German and French. It is an understandable request. Network discovery, inventory, and documentation can be technically demanding topics. When the interface speaks the language your team uses every day, working with the product becomes more comfortable and more accessible.
For a long time, however, our answer had to be a careful “not yet.” This was not because we underestimated the value of localization. The challenge was that the established way of adding translations did not fit the way JDisc Discovery is developed and released.
We release frequently. Our customers benefit from weekly improvements, fixes, and new capabilities, and we want to keep that pace. A conventional translation workflow would have added a handover process in the middle of each release week: identify changed text, prepare files, send them to a translation provider, wait for the result, review it, and merge it back into the product. That is a sensible process for many teams. For us, it would have become a recurring bottleneck.
Artificial intelligence gave us a different route. With a carefully defined workflow, clear product-specific language rules, and a small amount of housekeeping data, we were able to translate our application while preserving the speed and reliability of our release process. This article explains the problem, the traditional approach, and the solution we built with Codex.
Why translations were difficult before AI
The first issue was technical. Like many mature applications, parts of our Java client contained text directly in the source code. A label such as Server hostname, a dialog question, or a button caption could appear where it was needed:
editPanel.addLabelValue("Server hostname", hostnameHelpLabel, true);
This is clear and convenient while developing in one language. The developer can immediately see what the user will see. But it is not a structure that can simply be translated into multiple languages.
To use a traditional localization approach, we would first have needed to find the relevant strings across the application and move them into external language files. These files commonly use Java property files and ResourceBundles. Each piece of text receives a key, and the product loads the matching language version at runtime.
That first migration alone would have touched thousands of places in a large codebase. Every direct string displayed to a user would have to be replaced with a lookup by identifier. We would also have to distinguish carefully between user-facing text and strings that are part of the program logic, internal constants, log messages, configuration values, or protocol-related data. Translating the wrong kind of string can do more than create an odd label—it can break functionality.
There was also a process problem. At JDisc, a release normally needs to be ready on Friday for publication on Sunday. With an external translation workflow, changed strings would have to be collected and sent out around Wednesday to leave time for translation and review. In practice, that would mean avoiding changes to relevant user-facing text for almost half the week. For a team that ships improvements every week, this is not a small constraint.
We therefore kept declining the request, even though we knew that German and French versions would be helpful to many users. The question was not whether translations mattered. The question was how to make them sustainable.
How conventional ResourceBundle translations work
The conventional Java solution is well established. Instead of placing visible text directly in the code, the code refers to a key. The actual wording is stored in one property file for each supported language.
For example, an English source file could contain:
ClientMainWindow.askResumeDisc=Do you really want to resume the discovery activity?
The German version would contain the same key with German text:
ClientMainWindow.askResumeDisc=Möchten Sie die Discovery wirklich wieder aufnehmen?
And the French version could look like this:
ClientMainWindow.askResumeDisc=Voulez-vous vraiment reprendre l’activité de découverte ?
When the application needs to display the message, it selects the file for the active locale and retrieves the entry using Java’s standard ResourceBundle mechanism:
String outputString = resourceBundle.getString("ClientMainWindow.askResumeDisc");
However, a proven model is not automatically the right model for every existing application and every release process.
The trade-offs behind traditional language files
Readability moves away from the code
Resource bundles improve separation, but they also make a source file less immediately readable. When a developer sees ClientMainWindow.askResumeDisc, they cannot see the message without opening another file and searching for the key. In a review, that adds a small interruption each time a visible text is changed.
With thousands of strings, keys also need a naming convention that remains understandable for years. That is possible, but it is work in its own right.
Keys are not always easy to trace
Maintaining a complete list of used entries can be harder than it first appears. Some applications construct keys dynamically:
String clientWindowBaseKey = "ClientMainWindow";
String messageSubkey = "askResumeDisc";
String labelKey = clientWindowBaseKey + "." + messageSubkey;
String outputString = resourceBundle.getString(labelKey);
A simple search for the final key may no longer find every use. The same is true when helper methods, constants, or different modules generate keys in different ways. The challenge is manageable, but it makes automated completeness checks more complex.
Changed and new text needs its own workflow
You normally do not want to send every string to a translation provider for every release. You need to find what has changed in the master language, extract only those entries, submit them, and merge the finished translations back into the target-language files. New entries require a similar process.
Version control can help identify file changes, but it does not automatically solve the operational steps around them. Each step is another opportunity for a missed entry, an outdated translation, or a merge conflict.
The release calendar becomes a dependency
The biggest issue for us was timing. Waiting for an external handoff is not inherently wrong; it is simply incompatible with a short, active release cycle when UI text can still change late in the week. It can force a team to freeze text early, delay a feature, or accept that some translations will lag behind the English version.
We wanted a process that lets the team keep working, while still treating translations as an integral part of the product—not as an afterthought.
Our goal: translation as part of development
As we gained experience using ChatGPT to create and translate text, we also started working with Codex in our development environment, IntelliJ IDEA. We learned how important it is to give AI a precise task, helpful context, and clear rules. Over time, we also began building a small library of reusable skills for recurring development tasks.
That led to a practical question: could we create a skill that recognizes user-facing strings in our source code, introduces translations where appropriate, and keeps those translations current automatically?
Our requirements were deliberately concrete:
- Translations should be available automatically, ideally within a few minutes.
- New user-facing strings should be found and translated.
- A changed English source string should trigger a new translation.
- Manually adjusted translations must be preserved.
- Exceptions must be possible. Not every string in the codebase is user-facing or safe to translate.
The key was not to ask AI to “translate everything.” The key was to define exactly what counts as a translatable label in JDisc Discovery, what must be left alone, and how the result is checked over time.
A translation object keeps the context close
Instead of moving every label into a separate property file, our solution uses a Translations object that holds the master text and its language variants together. English remains the master language.
Each translation receives a unique identifier. A readable key would work, just as it does in a property file. We chose UUIDs because their job is not to describe the text; their job is to give one specific string occurrence a stable identity while the text itself evolves.
Here is a simplified example:
// Create a translation instance with a given id.
String translation = Translations.of("Configurations")
.id("efe093de-2eba-43ee-a69b-fb9a9f9dbc79")
.de("Konfigurationen")
.fr("Paramétrage");
// Now get the actual string for the current locale:
Locale locale = Locale.getDefault();
String translatedText = translation.getLabel(locale);
If no locale is set, or no translation exists for that locale, the object returns the English master text. This gives us a safe and understandable fallback. A user does not see an empty label merely because a language entry is missing.
The approach also keeps a useful amount of context in one place. A reviewer can see the English phrase, the German and French choices, and the identifier without moving between several files. For a mature application being localized after years of development, that matters.
Hashes turn changes into a clear decision
The stable ID solves one part of the problem: it tells the automation which source-code occurrence it is looking at. To decide whether a translation needs attention, we maintain a small housekeeping file alongside the source code.
For each translation, the file records hashes for the source and target texts. The most important fields are:
sourceHash, which represents the English master text when it was last translated.targetHash, which represents the translated text when it was last processed.
The next time the skill runs, it compares the current values with the stored hashes. If the English text for a given ID has not changed, nothing needs to be translated again. If it has changed, the skill knows that the related German and French text may need an update.
There is an equally important safeguard: manual edits. In rare cases, a person may improve or deliberately override a translated string. If the target text no longer matches its stored hash, that is a signal that someone changed it intentionally. The automation does not simply overwrite that work.
This is a small technical detail with a large practical benefit. The workflow no longer needs a person to compare long lists manually. It has a reliable basis for answering a simple question: does this particular translation need work now?
Review remains part of a reliable process
Automation does not mean accepting every result without looking at it. Alongside the housekeeping file, our process produces a Markdown file containing the actual translations. It gives us a quick review surface: instead of reading scattered source files, we can scan the translated labels together and spot wording that does not match our product language.
The quality of that review starts with the instructions given to the skill. We keep product-specific language guidance in knowledge files for Codex. These rules define what should be translated, which terms should remain in English, and when a phrase needs additional context. This is especially useful in IT. A word that has a perfectly valid German translation is not always the term German IT professionals use in their daily work. The French choice may be different again.
The result is not a generic translation layer. It is a repeatable process shaped around JDisc Discovery terminology and the expectations of our users.
Applying the workflow across an existing codebase
At first glance, wrapping labels in a translation object may look like extra work. That is exactly where the skill makes the difference.
It searches the source code for user-facing strings that are still hard-coded. When it finds one that meets the defined rules, it can create the required Translations instance, assign an ID, and generate the language entries. This means developers do not have to remember every part of the localization procedure while they work on a feature.
The skill also has to know what not to touch. Internal log messages, string constants that are used by the code itself, configuration names, identifiers, and similar values should not become product translations by accident. Our experience is that strict rules are better than overly broad automation. It is safer to leave an uncertain string in English for review than to translate a value that controls program behavior.
When we discover an exception, we add it to the rules. In that way, the skill becomes more useful over time without turning into a black box. The team understands what it is expected to do, and the process remains auditable in version control.
This philosophy is consistent with how we develop JDisc Discovery generally: automate what can be automated, but make the behavior transparent and keep people in control where judgment is needed. You can see the same focus on practical, ongoing improvement in our development news and in the product’s regular release cadence.
What changed for our release cycle
The most important outcome is not simply that JDisc Discovery can now display German and French labels. It is that translation no longer needs to interrupt development for several days.
When a label is added or changed, the automation can identify it, apply the relevant language guidance, and generate translations in minutes rather than requiring an external handover. Because hashes identify the changed source text and protect manually modified target text, the process focuses on the entries that genuinely need attention.
That lets us keep the weekly cadence that is central to how we deliver improvements. JDisc Discovery is designed to make complex IT environments easier to understand; the same principle matters inside our own development process. A workflow that is clear, reviewable, and quick to run is far more likely to remain dependable as the product grows.
For customers, localization is another way of making the product easier to use. For the development team, it is a good example of how AI can remove repetitive coordination work without replacing engineering judgment.
From product labels to documentation
There is still more to do. Our user manual is maintained in the headless CMS Strapi and currently contains English text, images, and chapter content. The same overall pattern can be applied there: read the English source content, translate it according to defined product rules, and use hashes to identify chapters that have changed since their last translation.
The details will be different because documentation has longer context and more editorial nuance than a button label. Still, the underlying approach is the same: preserve a clear master version, detect meaningful changes, protect intentional manual edits, and make review easy.
We see this as a practical next step toward making JDisc Discovery and its documentation more accessible to international teams—without slowing down the delivery of the improvements they rely on.
Conclusion
For years, traditional localization looked like a necessary but unrealistic project for our release model. It would have required a large code conversion and introduced a recurring dependency on external translation timing.
AI and Codex helped us take a more direct path. By combining a dedicated translation object, stable IDs, hash-based housekeeping, focused review files, and strict product-specific rules, we made translations part of the development workflow. New labels can be found automatically, changed English text can be identified reliably, and manual edits remain protected.
Most importantly, we were able to establish the process and translate the complete software within two weeks—while keeping our short release cycles intact. It is a useful example of AI in software development: not a replacement for careful engineering, but a practical tool that helps a team solve a long-standing problem in a way that fits its real day-to-day work.
If you would like to see how JDisc Discovery supports transparent, well-documented IT environments, you can download a free trial or book a personal demo.
Frequently Asked Questions
The following questions address the practical side of AI-assisted localization in JDisc Discovery. They explain what the workflow automates, what still requires review, and why the underlying IDs and hashes are important for reliable releases.
ResourceBundles are a proven Java localization mechanism. In our case, introducing them across an existing application would have required changing many thousands of direct string usages and adding an external translation handover process that did not fit our weekly release schedule.
The ID gives one specific source-code occurrence a stable identity. It allows the automation and its housekeeping file to recognize the same label even when the wording changes over time.
The stored sourceHash no longer matches the current English text. The skill then recognizes that the related translation needs to be reviewed and translated again according to the defined language rules.
The workflow checks the target hash as well. When a target string differs from the stored value, it signals a manual change, so the automation does not automatically replace it.
No. It is deliberately strict. The workflow focuses on user-facing text and excludes internal log messages, code-related constants, and other strings that should not be translated. Exceptions can be added to the rules as they are discovered.
The process produces a Markdown review file containing the translations. Product-specific knowledge files define language guidance, including which technical terms should remain in English and where a language-specific wording is needed.
No. AI reduces repetitive detection and translation work, while the review file and clear rules keep people involved in terminology, exceptions, and quality decisions.
Yes, that is the next area we plan to address. The manual is managed in Strapi, and the same hash-based approach can help identify English chapters that need an updated German or French version after changes.




