mirror of
https://github.com/mupen64plus/mupen64plus-oldsvn.git
synced 2025-04-02 10:52:35 -04:00
299 lines
6.9 KiB
C
299 lines
6.9 KiB
C
/***************************************************************************
|
|
translate.c - Handles multilanguage support
|
|
----------------------------------------------------------------------------
|
|
Began : Sun Nov 17 2002
|
|
Copyright : (C) 2002 by blight
|
|
Email : blight@Ashitaka
|
|
****************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "translate.h"
|
|
#include "main.h"
|
|
#include "util.h"
|
|
#include "config.h"
|
|
|
|
#include <dirent.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <iconv.h>
|
|
#include <errno.h>
|
|
|
|
// types
|
|
typedef struct
|
|
{
|
|
char *orig; // original, english string
|
|
char *trans; // translated string to find entry
|
|
} translation_t;
|
|
|
|
typedef struct
|
|
{
|
|
char *name;
|
|
list_t translations;
|
|
} language_t;
|
|
|
|
// globals
|
|
static list_t g_LanguageList = NULL;
|
|
static language_t *g_Language = NULL;
|
|
|
|
// static functions
|
|
static language_t *
|
|
tr_load_language( const char *filename )
|
|
{
|
|
FILE *f;
|
|
language_t *lang;
|
|
translation_t *trans;
|
|
char line[2048];
|
|
char iso[200];
|
|
char *iso_start;
|
|
size_t inbytes;
|
|
char utf8[1024];
|
|
char *utf8_start;
|
|
size_t outbytes;
|
|
char *p, *p2;
|
|
iconv_t cd;
|
|
|
|
f = fopen( filename, "r" );
|
|
if( !f )
|
|
return NULL;
|
|
|
|
if((cd = iconv_open("UTF-8", "ISO-8859-1")) == (iconv_t)-1)
|
|
{
|
|
fclose(f);
|
|
perror(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
lang = (language_t *)malloc( sizeof( language_t ) );
|
|
memset( lang, 0, sizeof( language_t ) );
|
|
|
|
while( !feof( f ) )
|
|
{
|
|
if( !fgets( line, 2048, f ) )
|
|
continue;
|
|
|
|
trim( line );
|
|
|
|
if( line[0] == ';' || line[0] == '\0' )
|
|
continue;
|
|
|
|
if( line[0] == '[' && line[strlen(line)-1] == ']' )
|
|
{
|
|
// convert language name to UTF-8
|
|
strcpy(iso, line + 1);
|
|
iso[strlen(iso)-1] = '\0';
|
|
|
|
iso_start = iso;
|
|
inbytes = strlen(iso);
|
|
utf8_start = utf8;
|
|
outbytes = 1024;
|
|
|
|
memset(utf8, 0, sizeof(utf8));
|
|
iconv(cd, &iso_start, &inbytes, &utf8_start, &outbytes);
|
|
|
|
// store language name
|
|
lang->name = malloc(strlen(utf8) + 1);
|
|
strcpy(lang->name, utf8);
|
|
continue;
|
|
}
|
|
|
|
p = strchr( line, '=' );
|
|
if( p )
|
|
{
|
|
// replace "\\n" by '\n'
|
|
while( (p2 = strstr( line, "\\n" )) )
|
|
{
|
|
*p2 = '\n'; // replace '\\' by '\n'
|
|
p2++;
|
|
strcpy( p2, p2 + 1 ); // remove 'n'
|
|
}
|
|
|
|
p = strchr( line, '=' ); // line may have changed
|
|
*p = '\0'; p++;
|
|
trim( line );
|
|
trim( p );
|
|
|
|
if( strlen( line ) == 0 || strlen( p ) == 0 )
|
|
continue;
|
|
|
|
// convert translated string to UTF-8
|
|
iso_start = p;
|
|
inbytes = strlen(p);
|
|
utf8_start = utf8;
|
|
outbytes = 1024;
|
|
|
|
memset(utf8, 0, sizeof(utf8));
|
|
iconv(cd, &iso_start, &inbytes, &utf8_start, &outbytes);
|
|
|
|
// save translation data
|
|
trans = (translation_t *)malloc(sizeof(translation_t));
|
|
trans->orig = strdup( line );
|
|
trans->trans = malloc(strlen(utf8) + 1);
|
|
strcpy(trans->trans, utf8);
|
|
|
|
list_append(&(lang->translations), trans);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
iconv_close(cd);
|
|
fclose(f);
|
|
return lang;
|
|
}
|
|
|
|
void
|
|
tr_delete_languages(void)
|
|
{
|
|
language_t *lang;
|
|
translation_t *trans;
|
|
list_node_t *lang_node,
|
|
*trans_node;
|
|
|
|
// free current list
|
|
list_foreach(g_LanguageList, lang_node)
|
|
{
|
|
lang = (language_t *)lang_node->data;
|
|
list_foreach(lang->translations, trans_node)
|
|
{
|
|
trans = (translation_t *)trans_node->data;
|
|
|
|
free(trans->orig);
|
|
free(trans->trans);
|
|
free(trans);
|
|
}
|
|
list_delete(&(lang->translations));
|
|
free(lang->name);
|
|
free(lang);
|
|
}
|
|
list_delete(&g_LanguageList);
|
|
}
|
|
|
|
// functions
|
|
static void
|
|
tr_load_languages( void )
|
|
{
|
|
language_t *lang;
|
|
char langdir[PATH_MAX], filename[PATH_MAX];
|
|
const char *p;
|
|
DIR *dir;
|
|
struct dirent *de;
|
|
|
|
// delete any existing list
|
|
tr_delete_languages();
|
|
|
|
// list languages
|
|
snprintf(langdir, PATH_MAX, "%slang/", get_installpath());
|
|
dir = opendir(langdir);
|
|
if(!dir)
|
|
return;
|
|
|
|
while((de = readdir(dir)))
|
|
{
|
|
p = strrchr(de->d_name, '.');
|
|
if(!p)
|
|
continue;
|
|
if(strcmp(p, ".lng"))
|
|
continue;
|
|
|
|
snprintf(filename, PATH_MAX, "%s%s", langdir, de->d_name);
|
|
lang = tr_load_language(filename);
|
|
if(lang)
|
|
{
|
|
list_append(&g_LanguageList, lang);
|
|
}
|
|
}
|
|
|
|
closedir(dir);
|
|
}
|
|
|
|
void tr_init(void)
|
|
{
|
|
list_t langList;
|
|
list_node_t *node;
|
|
char *language;
|
|
const char *confLang;
|
|
|
|
// read in language file data
|
|
tr_load_languages();
|
|
|
|
// set language based on config file
|
|
langList = tr_language_list();
|
|
confLang = config_get_string( "Language", "English" );
|
|
list_foreach(langList, node)
|
|
{
|
|
language = (char *)node->data;
|
|
if(!strcasecmp(language, confLang))
|
|
tr_set_language(language);
|
|
}
|
|
// free language name list
|
|
list_delete(&langList);
|
|
}
|
|
|
|
list_t
|
|
tr_language_list( void )
|
|
{
|
|
language_t *lang;
|
|
list_node_t *node;
|
|
list_t list = NULL;
|
|
|
|
list_foreach(g_LanguageList, node)
|
|
{
|
|
lang = (language_t *)node->data;
|
|
list_append(&list, lang->name);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
int
|
|
tr_set_language(const char *name)
|
|
{
|
|
language_t *lang;
|
|
list_node_t *node;
|
|
|
|
list_foreach(g_LanguageList, node)
|
|
{
|
|
lang = (language_t *)node->data;
|
|
if(!strcasecmp(name, lang->name))
|
|
{
|
|
g_Language = lang;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
g_Language = NULL;
|
|
return -1;
|
|
}
|
|
|
|
const char *
|
|
tr( const char *text )
|
|
{
|
|
list_node_t *node;
|
|
translation_t *trans;
|
|
const char *ret = text;
|
|
|
|
if( g_Language )
|
|
{
|
|
list_foreach(g_Language->translations, node)
|
|
{
|
|
trans = (translation_t *)node->data;
|
|
if(!strcasecmp(text, trans->orig))
|
|
{
|
|
ret = trans->trans;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|