inkle / ink

inkle's open source scripting language for writing interactive narrative.
http://www.inklestudios.com/ink
MIT License
4.11k stars 491 forks source link

[Discussion] Localization of an ink-based game #98

Open Ludipe opened 8 years ago

Ludipe commented 8 years ago

Hey there!

We're developing our main project using ink and we're loving it. Our studio is based in Madrid and, since most of the writers prefer working in Spanish, we're looking for somebody to do a proper English translation.

We could get every single piece of text, export it to excel and have them translate that, but we're aiming for quite a lengthy game, I guess it would take quite some time from development.

We could also try having them working with a copy of the .ink files, though we might need to check all the syntaxis later (would that be a huge pain in the ass? not sure).Translators would need to work a bit harder, since they would need to learn the basics of ink, but I guess it would also be easier for them to understand the meaning of each line of text.

We'll be working close to them to see what method is easier, but perhaps there's a better solution we haven't thought of. This topic might also be useful for more devs in the future so, what's your take on this? How would you do it?

joethephish commented 8 years ago

Hey! Yeah, there have actually been a few discussions on this topic, for example #89. The summary is: we don't currently have an "official" tried and tested solution since we've never attempted it ourselves. Our preferred approach would be to find a localisation team who would be willing to learn ink, and possibly encourage get their hands dirty with a little bit of logic tweaks, if they're necessary due to word order changing or even fixing word endings etc.

On top of that, we've wondered about the possibility of creating verification tools to make sure that the translators don't accidentally break the high level structure of the ink, though it may be tricky to distinguish between breaking the high level flow, and tweaking the word by word language.

Ludipe commented 8 years ago

Oh, thanks! Missed that post.

As said there, anything that would make localization easier would be very helpful. In the meantime we'll work close to translators, trying to make sure they understand the basics.

rubereaglenest commented 8 years ago

My experience with other scripts or languages for IF tell me that yes, extract strings of text and localise them with a external tool or database is not recommended because that is not as translating a normal game where you have a lot of code and then a little "It's dangerous to go alone! Take this". In IF games you have a lot of text and little code or logic, more true if it is a CYOA kind rather than a world model based game.

I have remaked and localised to Spanish and English two games of 1986 Rod Pike's Dracula. The first I opted to have two different scripts, one for each language. This is obviously optimal because you can code in each localisation each idiosyncrasy of its language. However I just recommend this approach if you have a completely finished game, because, later, coming back and adding a feature, you must then cycle for each localisation adding that piece of code, and that is, a king of development hell.

For the second part of the game I opted for including in each string of text every language (just two of them), and I used a python parser to filter through each language and compile in one language or another. That was better but because I was the sole dev. If I would pass the code to a translator, then they could mess with the code.

In both cases I ended with two separate builds, one per language.

With Ink, if you have a finished script, you can hand it to translators and later run the proper script for each language. but that do not prevent from creep through all scripts adding new features or bugfixes.

So, I think the ideal approach would be an editor that allow to add strings of translations to each text bit, so you can easily track each language in context, and that it handles smoothly a database of localisation that is invisible to the script user.

This is not going to help :) but, my two cents.

rubereaglenest commented 8 years ago

More on the approach I think would be ideal for Ink.

Here is some code from Dracula part 2, the remake I told you above: (Inform 6)

#ifdef VO; !! ---- ENGLISH ----
LocalidadExterior locNieve "I am standing on a snow covered road."
    with irrelevante 'snow',
    descripcion "Next to me is a fine coach, pulled by four magnificent black horses. This is to take me to the castle.",
    antes [;
     Examinar: if (uno==obj_arriba) <<Examinar objSnow2>>;
        if (uno==obj_abajo) <<Examinar objCarretera>>;
    Excavar: "I dig the cold snow and I found my hands freeze. Pain runs through my fingers as my blood pumps through my veins against the cold. Apart from that, I found nothing here, and the hole refills with snow.";
    ],
    no_puedes_ir "Only a coach could venture across the snowy landscape.";
#ifnot; !! ---- EN CASTELLANO ----
LocalidadExterior locNieve "Estoy en una carretera cubierta de nieve."
    with irrelevante 'nieve',
    descripcion "A mi lado hay un excelente carruaje, tirado por cuatro magníficos caballos negros. Está aquí para llevarme al castillo...",
    antes [;
     Examinar: if (uno==obj_arriba) <<Examinar objSnow2>>;
        if (uno==obj_abajo) <<Examinar objCarretera>>;
    Excavar: "Cavo en la fría nieve y encuentro mis manos congeladas. Un dolor recorre mis dedos cuando mi sangre bombea a través de mis venas contra el frío. Aparte de eso, no encuentro nada interesante, y el agujero vuelve a llenarse de nieve.";
    ],
    no_puedes_ir "Sólo un carruaje puede aventurarse por el paisaje nevado.";
#endif;

This is a first approach. Using compiler directives I duplicate objects, one per language. But this repeat whole blocks of code, and if you must fix or add a feature then you must make the change twice. Not much trouble, but sometimes in the log hours of fixing and updating, it is not rare to forget to change one of the languages in any object.

If you want to go further and split at string level, this was not enough, because compiler directives must be used outside of objects. You can't split and fork inside an object in Inform 6, so I need to use a python parser to add tags that fork the code by language, let's cast an eye to this example from a game in German, with English, and a pending Italian localization:

Object -> Stein 
:DE
   "Stein"
:EN
   "stone the size of your fist"
:IT
   "stone the size of your fist"
:
with

:DE
 dekl 3,
 adj "faustgroß",
:
 name
    :DE 'faustgross' 'gross' 'rund' 'glatt' 'stein',
    :EN 'stone' 'big' 'fist' 'size' 'sized' 'fist-sized',
    :IT 'stone' 'big' 'fist' 'size' 'sized' 'fist-sized',
    :
 description
    :DE "Der Stein ist so groß wie eine Faust
            und außergewöhnlich glatt und rund.",
        :EN "The stone is about as bis as your fist 
            and it is incredibly smooth and perfectly round.",
        :IT "The stone is about as bis as your fist 
            and it is incredibly smooth and perfectly round.",
        : 
 initial
    :DE "^In der Nähe des Schreins liegt ein
            glatter, runder Stein im Gras.",
        :EN "^A smooth, round stone is lying in the grass
            by the shrine.",
        :IT "^A smooth, round stone is lying in the grass
            by the shrine.",
        :
:DE
 has male;
:
;

So, I think this is the optimal way. If Ink would allow something like compiler directives or tags that allow to split the code arbitrary to insert strings of different languages, that would be a definitive solution for the problem at hand. Lets put an imaginary example, adapting an example of the Ink tutorial:

- :EN I looked at Monsieur Fogg 
  :ES Miré al señor Fogg
*  :EN  ... and I could contain myself no longer.
    'What is the purpose of our journey, Monsieur?'
    'A wager,' he replied.
  :ES ... y no me pude contener más.
         '¿Cuál es el propósito de nuestro viaje, Señor?
         'Una apuesta', respondió.
    * *     :EN  'A wager!'[] I returned.
            He nodded.
             :ES '¡Una apuesta!'[] repetí sin salir de mi asombro.
             El señor fog afirmó sin inmutarse.
            * * *   :EN 'But surely that is foolishness!'
                     :ES 'Pero, ¡esto es una locura!'
            * * *  :EN 'A most serious matter then!'
                    :ES '¡Ciertamente, un asunto de lo más serio!'
            - - -   :EN He nodded again.
                     :ES Él afirmo de nuevo.
            * * *   :EN 'But can we win?'
                     :ES 'Pero, ¿podemos ganar?'
                    :EN 'That is what we will endeavour to find out,' he answered.
                     :ES 'Eso es lo que vamos a averiguar.'
            * * *   :EN 'A modest wager, I trust?'
                     :ES 'Una apuesta modesta, espero...'
                    :EN 'Twenty thousand pounds,' he replied, quite flatly.
                     :ES 'Dos mil libras,' respondió, 
            * * *   :EN I asked nothing further of him then[.], and after a final, polite cough, he offered nothing more to me. <>
                     :ES No pregunté nada más[.], y tras un final y educado ejem, no me ofreció nada más. <>
    * *     :EN 'Ah[.'],' I replied, uncertain what I thought.
             :ES 'Ah[.'],' repliqué, sin saber qué pensar.
    - -     :EN  After that, <>
             :ES  Tras eso, <>
*   :EN ... but I said nothing[] and <> 
    :EN ... pero no dije nada[] y and <> 
- :EN we passed the day in silence.
  :ES pasamos el día en silencio.
- -> END

As you can see this is another kind of development hell. But I think that a proper IDE could do this internally and properly filter per language so a writer has not to make this to this level.

And finally the message I want to transmit is that if Ink would have compiler directives, or the ability to fork the code previous to parsing it with Ink, then authors could try to handle the localisation problem in the way they considere better.

Ludipe commented 8 years ago

Wow, that's very helpful, thanks!

We're going to start with different .ink files for each language, we're only aiming for English and Spanish. Duplicating each line on the same line makes everything messier and harder to navigate, so we'll just duplicate every file and have the translators use the copy.

We'll have to keep an organized database for changes, so we don't forget to make every change on both .ink files.

On the other thread somebody sugested having an IDE which blocked ink syntaxis from being modified, while I get the point that it may be necessary for translators to change some of the syntaxis maybe it could be helpful. If it's something that happens every once in a while developers could take care of it manually. Everything depends on how much time devs need to spend fixing those lines and how many issues prevents for translators.

micabytes commented 8 years ago

When I had people localize story scripts for my previous game (not Ink scripts, but a very similar scripting language), what I did was to use a very simple convention for script constructs (e.g., writing all variables in ALL_CAPS or similar), and then I simply instructed the translators to avoid translating anything which was written using the chosen convention and created seperate files. This worked very well, with relatively few problems.

Fahrengeit commented 8 years ago

I think you don't really need to teach of Ink to translator — most of .ink file is text anyway, and you can say, what things translators shouldn't change. And with help of Sublime you can make different color for all objects that are not text, this can be very helpful too. There is another problem, I think — if you are making very flexible sentences with lot of variable text, then you may stumble with translation. That's when it's better to have a translator who knows Ink. And a lot of things depends on the language. I've translated my demo from Russian to English, and it had even more problems because of different realisations of direct speech in text. So I couldn't give it anyone else who didn't know how to work with Ink.

Oreolek commented 3 years ago

Idea: extend language with backticks (`)

Backticks would mark a translatable line (would look like this: `'A wager!'[] I returned.` ) Inevitably, lines would contain bits of logic markup but only bits of it.

And add a translation mode to Inklecate, so that it gets two files - .ink and a translation, replaces all translatable lines with translations and only then compiles the code to JSON.

It's possible to build a gettext extractor/translator around Ink, as long as the language won't update and assign its own meaning to the operator.