T
The Shopkeeper
Guest
Do you know any CSV Localization tutorial that you recommend?
The GMS help pages teaches you to read files, but not to work with keys and read all the content belonging to a key.The GMS help pages will get you 90% of the way there.
This will show you how to read in a text file and start stepping through it and storing data.
draw_text(x,y,scr_text_get_string(text.action_critical_hit));
enum text
{
action_critical_hit,
interact_door_locked,
interact_treasure_empty,
etc....
}
/*
The top cell in each row must be filled to get the contents from that row
*/
/// @arg file
/// @arg seperator
var file = file_text_open_read(argument0);
var seperator=argument1;
var line
var grid;
var row=0;
var column;
var columns;
var seperator_pos;
var val;
grid=ds_grid_create(0,0);
do
{
// Get the current line
line=file_text_readln(file);
// If this is the first line, count seperators to get the width
if row==0 columns=string_count(seperator,line)+1;
// Resize the grid every time we have stuff to add
ds_grid_resize(grid,columns,row+1);
// Parse through each column
for (column=0; column<columns; column+=1)
{
//Find seperator
seperator_pos=string_pos(seperator,line);
// Should be commas
if (column<columns-1)
{
// Get value
val=string_copy(line,1,seperator_pos-1);
// Remove from line
line=string_delete(line,1,seperator_pos);
}
// Last line. Make sure line break is removed
else val=string_copy(line,1,string_length(line)-2);
// Add to grid
ds_grid_add(grid,column,row,val);
}
row+=1;
} until file_text_eof(file);
file_text_close(file);
return grid;
ds_grid_destroy(grid);
/// Get all data from csv
scr_show_debug_message("scr_text_import()");
var grid=scr_load_csv_ext("strings.csv",";"); // I use semicolons to separate my csv file because the text can include commas
var size=ds_grid_height(grid);
var contents;
// Clear out any old data
ds_list_clear(global.ds_text);
// Make list from correct column
for (var i=1; i<size; i+=1) // 1 because headers are on row 0
{
contents=ds_grid_get(grid,global.settings_language,i);
// If empty, get english text by default
if (string_length(contents)<1)
{
contents=ds_grid_get(grid,1,i);
}
ds_list_add(global.ds_text,contents);
}
// Make list of all available languages
var width=ds_grid_width(grid);
for (var i=1; i<width; i+=1) // 1 because enums are on column 0
{
global.settings_languages[i]=ds_grid_get(grid,i,0);
}
// Clean up
ds_grid_destroy(grid);
gml_pragma("forceinline");
/// @arg enumerator
var enumerator=argument0;
if (is_undefined(enumerator)) return "undefined";
else return ds_list_find_value(global.ds_text,enumerator);
One important thing you're missing is a "context" field (which would be read by the translators and not used by the game itself)... sometimes the same word can have different meanings, and you can get stupid-looking translation errors if the wrong meaning is picked... Dark Souls III had the "bow" gesture (lean forward to show respect) translated as a "bow" weapon (piece of bent wood that launches arrows using tensile properties) in the french translation, for instance. Japanese and a number of other languages have different speech patterns depending on a character's background (like adding or removing honorifics depending on how blunt / formal the character is, or changing the genus of words like "me" and "you" depending on gender and social standing of the person that is being referred to) and omitting this context and just guessing will make the dialogue come off as unnatural.First, my CSV is set up like this...
Thank you very much for sharing your work, this allowed me to organize my ideas. I am very grateful.I'll walk you through how I do it. I'm bored and maybe someone can critique my method. The goal is to be able to use a recognizable enumerator and get the correct string in it's place.
That depends on the size of your project. A "context" checkbox is ideal, but is it necessary in a 300 string project? And it also depends on whether the translator is the same writer. But I'll apply your idea to my project, XDOne important thing you're missing is a "context" field (which would be read by the translators and not used by the game itself)... sometimes the same word can have different meanings, and you can get stupid-looking translation errors if the wrong meaning is picked... Dark Souls III had the "bow" gesture (lean forward to show respect) translated as a "bow" weapon (piece of bent wood that launches arrows using tensile properties) in the french translation, for instance. Japanese and a number of other languages have different speech patterns depending on a character's background (like adding or removing honorifics depending on how blunt / formal the character is, or changing the genus of words like "me" and "you" depending on gender and social standing of the person that is being referred to) and omitting this context and just guessing will make the dialogue come off as unnatural.
Ideally, the translators should ask you for this type of context to make sure they get it right (if someone just takes a bunch of text and outputs a translation without asking for feedback at all, chances are they're just machine-translating it and hoping you don't notice...), but having any necessary context right in the excel sheet should speed up the process. It also might help you avoid issues where strings are reused in places that makes sense in the original version but not in translations (for instance, if you have a string for "chest" (in the treasure sense) and you decide to reuse it in a scene where a character complains about chest pains, it will stop making sense in a lot of other languages... for instance swedish using "[skatt]kista" for the former and "bröst[korg]" for the latter, both of which also has an optional part that can be dropped in less formal contexts at the expense of making things a bit more unclear! (The part in [square brackets] is the optional bit))
TL;DR translations are messy, you need to think about a lot more stuff than just how to get your text into the game.
It's probably not even necessary in a 300,000 word RPG, but it's always easier to ignore something unnecessary but present than to reverse-engineer something necessary but absentThat depends on the size of your project. A "context" checkbox is ideal, but is it necessary in a 300 string project? And it also depends on whether the translator is the same writer. But I'll apply your idea to my project, XD
I noticed that, I don't really like the idea of writing ID by ID to an enum either. I decided to store the texts of the selected language from the CSV to a DS_Map to avoid writing all the IDs manually. IMO is quite practical.I should point out that my method is a little wasteful in that I read every column into a grid each time and then discard the excess languages instead of just figuring out which column we need first and retrieving only that. It was just easier this way. Suddenly I want to fix it...