Skip to content

Conversation

@reservation-v
Copy link

This PR implements full localization support for Oh-my-git!

Summary

The goal is to allow non-English speakers to play the game and enable community to contribute translations easily.

Russian and Brazilian are added as the proof-of-concept languages.
In Brazilian all keys are "TRANSLATED" placeholders, Russian is translated by AI.

The following changes are included:

  1. Infrastructure for CSV-based translations.
  2. Font replacement (Cyrillic support).
  3. OptionButton in title.tscn for language switching.
  4. Refactor the game menu into a standalone Global_menu scene.
    This scene is now in both main.tscn and level_select.tscn.
  5. Adjust TextEdit nodes to prevent text from overlapping with the "Close" and "Save" buttons.

Plan

The next step will be migrating from .csv to the .pot (Gettext) file format.
Using .pot is the industry standard for localization and is officially recommended by the Godot documentation:
https://docs.godotengine.org/en/stable/tutorials/assets_pipeline/importing_translations.html#doc-importing-translations

PR closes #18

@blinry
Copy link
Member

blinry commented Nov 27, 2025

Hey, thanks for working on this! We're currently don't have a lot of time to work on this project, but we plan to look at this PR on Monday, and give you feedback!

@reservation-v
Copy link
Author

Hey, @blinry! Did you take a look at my changes?

@blinry blinry mentioned this pull request Dec 2, 2025
@blinry
Copy link
Member

blinry commented Dec 2, 2025

Yes! @bleeptrack looked at this PR yesterday, and also at #152, another attempt at a localization feature.

Cool that you're working on this – people still occasionally ask for translated levels, or express interest in translating them! :) So this would be very cool to see.

We want to make sure we get the translation feature right, so that potential translators and players will have a good time with it. So here's some thoughts, curious what you think about them:

CSV vs .po format

You already mentioned yourself that relying on gettext and .po files would be a great option – it avoids file conflicts when multiple people translate at the same time, compared to the CSV file with multiple columns.

Are you familiar with the gettext format and .po files? #152 already relied on this, maybe you can take inspiration.

Technique for translating levels

In #152, full translated level files where kept in a parallel directory structure – there would be a intro/it/commit file, in addition to intro/en/commit, for example. This has the upside that all level files make sense "on their own", but the downside that, if (for example) someone fixes a regular expression in the condition of a level, it would now need to be fixed in all translation – the translations can start to "lag behind".

Because of that, we think that your approach of translating the individual snippets of text in levels makes a lot of sense! 🎉 One downside is that the levels can't be "fully customized" to, for example, provide more culturally appropriate content in other languages. If anyone has thoughts on that, I'd be curious to hear them, but for now, we could go ahead with the approach in this PR!

@@short_keys_42@@ vs @@marking the original@@

Your approach of substituting all English strings with numbered keys has a downside: It's now hard to understand what's going on in a level file when reading it (example). To understand the level, you have to hunt down the short key in the English translation file; I don't think that's a good option.

Instead, could we do it like commonly is done in gettext with a _() function? Where we'd mark all strings that should be translated with a specific syntax – you picked the double-@@, does that have any inspiration from somewhere?

So instead of

title = fork_title_103
cards = checkout commit-auto

[description]

fork_description_104

[setup]

mkdir cage
echo "@@setup_auto_196@@" > cage/lion

it would be

title = @Make parallel commits@@
cards = @@checkout commit-auto@@

[description]

@@Did you know that creating parallel timelines is perfectly legal and safe? It's true!

Can you find out when things went wrong in this zoo? Then, go back to the last good commit and create a parallel universe where everyone is happy!@@

[cli]

@@The blue animal represents a concept known as the "HEAD pointer" in Git: It shows you which commit is the current one.

Here's a cool trick to go to the previous commit: 

    git checkout HEAD^

You can also go back two commits by typing, for example: 

    git checkout HEAD~2@@

[setup]

mkdir cage
echo "@@Looks very hungry.@@" > cage/lion

The translation mechanism could then use the full English text as a lookup when the language is changed.

For things like labels and buttons, Godot seems to do that automatically, so we wouldn't need cryptic short tags there, as well.

One downside of this approach is that changing the English original invalidates all translations (I think). But gettext does work like that, I think, and maybe even offers some help.

Do you see other downsides? Does this approach make sense to you?

Is @@ the best markers we could use? Or could there be conflicts with the content in any situation? It seems pretty important to pair them together correctly, but that seems doable.

Further questions

  • While working on this PR, did you encounter situations where singular/plural forms would be a translation problem? In other projects where I was in contact with i18n, that was occasionally something very specific to look out for. But maybe it's a non-issue here?
  • You said the Russian translation was translated by AI. How would we make sure that it's reasonable/preserves the intent of the original descriptions? Get some beta testers for each language?

A note on the maintenance status

I now tried to clarify this in the main README a bit better – our time which we can contribute is currently limited, and we might take a while to get back to you. We hope for your patience.

But again, very cool to see you work on this; let us know what you think!

@reservation-v
Copy link
Author

Thanks for the quick and detailed response!

Regarding the syntax:

Using _() is a good decision. It is the industry standard, and implementing a parser for it is absolutely feasible. I will rewrite the level parser to extract text wrapped in _().

So, the level file would look like this:

title = _(Make parallel commits)

cards = checkout commit-auto

Basically, I will wrap all translatable text (titles, descriptions, hints) in _(). Untranslatable content, like specific git commands or internal IDs, will remain as is.

Regarding @@ markers:

As far as I know they are default symbols used for placeholder in templates. Switching to _() avoids confusion and makes the file look cleaner for developers.

Answers to your questions

1. Singular/Plural forms and linguistic issues:

  • I did encounter a related issue with grammatical cases (which are complex in Russian). For example, a win-condition check was failing because it was grep for a specific word, but in the translated Russian description, that word changed its ending due to grammar.

Solution:

  • I will refactor the logic so that grep checks against language-agnostic keys or properly localized strings to prevent gameplay logic from breaking.

2. Translation Quality:

  • The AI translation in the current commit was just a placeholder to test the technical pipeline (font rendering, UI fitting, etc.).
  • For the final version, I have enlisted help from my friends - translators at ALT Linux Team. They have experience with open-source localization, so the quality will be high and culturally appropriate.

Next steps:

I will proceed with refactoring the code to support .po files and the _() syntax in levels.

Will be in touch!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for i18n ?

2 participants