New "dynamic" i18n menu.
Now both UI translation menu (in userprefs) and isocodes are defined in a text file (release/datafiles/locale/languages), parsed at lunchtime. This way: * No more need to edit Blender code each time we want to add an new language or reorganize the existing menu; * Translators can easily add a new language for testing, by just editing the text file, so no more need to ask to change Blender code and wait for a new build to see your new translation work in Blender! Remaining todo: * Commit i18n py tools * Update wiki doc!
This commit is contained in:
@@ -49,9 +49,13 @@ const char *BLF_pgettext(const char *context, const char *message);
|
||||
|
||||
/* Search the path directory to the locale files, this try all
|
||||
* the case for Linux, Win and Mac.
|
||||
* Also dynamically builds locales and locales' menu from "languages" text file.
|
||||
*/
|
||||
void BLF_lang_init(void);
|
||||
|
||||
/* Free languages and locales_menu arrays created by BLF_lang_init. */
|
||||
void BLF_lang_free(void);
|
||||
|
||||
/* Set the current locale. */
|
||||
void BLF_lang_set(const char *);
|
||||
/* Get the current locale (short code, e.g. es_ES). */
|
||||
@@ -60,6 +64,9 @@ const char *BLF_lang_get(void);
|
||||
/* Set the current encoding name. */
|
||||
void BLF_lang_encoding(const char *str);
|
||||
|
||||
/* Get EnumPropertyItem's for translations menu. */
|
||||
struct EnumPropertyItem *BLF_RNA_lang_enum_properties(void);
|
||||
|
||||
/* translation */
|
||||
int BLF_translate_iface(void);
|
||||
int BLF_translate_tooltips(void);
|
||||
|
||||
@@ -25,8 +25,10 @@ set(INC
|
||||
.
|
||||
../blenkernel
|
||||
../blenlib
|
||||
../blenloader
|
||||
../editors/include
|
||||
../makesdna
|
||||
../makesrna
|
||||
../imbuf
|
||||
../../../intern/guardedalloc
|
||||
)
|
||||
|
||||
@@ -4,7 +4,8 @@ Import ('env')
|
||||
|
||||
sources = env.Glob('intern/*.c')
|
||||
|
||||
incs = '. intern #/intern/guardedalloc ../blenkernel ../blenlib ../makesdna ../imbuf ../editors/include'
|
||||
incs = '. intern #/intern/guardedalloc ../blenkernel ../blenlib ../blenloader'
|
||||
incs += ' ../makesdna ../makesrna ../imbuf ../editors/include'
|
||||
incs += ' #/extern/glew/include'
|
||||
incs += ' ' + env['BF_FREETYPE_INC']
|
||||
incs += ' ' + env['BF_GETTEXT_INC']
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "BLF_api.h"
|
||||
|
||||
#include "BLF_translation.h" /* own include */
|
||||
|
||||
#ifdef WITH_INTERNATIONAL
|
||||
@@ -46,15 +45,16 @@
|
||||
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_vec_types.h"
|
||||
#include "RNA_types.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_linklist.h" /* linknode */
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#define SYSTEM_ENCODING_DEFAULT "UTF-8"
|
||||
#define FONT_SIZE_DEFAULT 12
|
||||
@@ -64,50 +64,120 @@ static char global_messagepath[1024];
|
||||
static char global_language[32];
|
||||
static char global_encoding_name[32];
|
||||
|
||||
/* Map from the rna_userdef.c:rna_def_userdef_system(BlenderRNA *brna):language_items */
|
||||
static const char *locales[] = {
|
||||
"", "",
|
||||
"english", "en_US",
|
||||
"japanese", "ja_JP",
|
||||
"dutch", "nl_NL",
|
||||
"italian", "it_IT",
|
||||
"german", "de_DE",
|
||||
"finnish", "fi_FI",
|
||||
"swedish", "sv_SE",
|
||||
"french", "fr_FR",
|
||||
"spanish", "es",
|
||||
"catalan", "ca_AD",
|
||||
"czech", "cs_CZ",
|
||||
"portuguese", "pt_PT",
|
||||
#if defined(_WIN32) && !defined(FREE_WINDOWS)
|
||||
"Chinese (Simplified)_China.1252", "zh_CN",
|
||||
"Chinese (Traditional)_China.1252", "zh_TW",
|
||||
#else
|
||||
"chs", "zh_CN",
|
||||
"cht", "zh_TW",
|
||||
#endif
|
||||
"russian", "ru_RU",
|
||||
"croatian", "hr_HR",
|
||||
"serbian", "sr_RS",
|
||||
"ukrainian", "uk_UA",
|
||||
"polish", "pl_PL",
|
||||
"romanian", "ro_RO",
|
||||
"arabic", "ar_EG",
|
||||
"bulgarian", "bg_BG",
|
||||
"greek", "el_GR",
|
||||
"korean", "ko_KR",
|
||||
"nepali", "ne_NP",
|
||||
"persian", "fa_IR",
|
||||
"indonesian", "id_ID",
|
||||
"serbian (latin)", "sr_RS@latin",
|
||||
"kyrgyz", "ky_KG",
|
||||
"turkish", "tr_TR",
|
||||
"hungarian", "hu_HU",
|
||||
"portuguese-brazilian", "pt_BR",
|
||||
"hebrew", "he_IL",
|
||||
"estonian", "et_EE",
|
||||
"esperanto", "eo", /* No country code for esperanto! ;) */
|
||||
};
|
||||
static const char **locales = NULL;
|
||||
static int num_locales = 0;
|
||||
static EnumPropertyItem *locales_menu = NULL;
|
||||
static int num_locales_menu = 0;
|
||||
|
||||
#define ULANGUAGE ((U.language >= 0 && U.language < num_locales) ? U.language : 0)
|
||||
#define LOCALE(_id) (locales ? locales[_id] : "")
|
||||
|
||||
static void free_locales(void)
|
||||
{
|
||||
if (locales) {
|
||||
int idx = num_locales_menu - 1; /* Last item does not need to be freed! */
|
||||
while (idx--) {
|
||||
printf("freeing %s\n", locales_menu[idx].identifier);
|
||||
MEM_freeN((void*)locales_menu[idx].identifier);
|
||||
printf("freeing %s\n", locales_menu[idx].name);
|
||||
MEM_freeN((void*)locales_menu[idx].name);
|
||||
printf("freeing %s\n", locales_menu[idx].description);
|
||||
MEM_freeN((void*)locales_menu[idx].description); /* Also frees locales's relevant value! */
|
||||
}
|
||||
MEM_freeN(locales);
|
||||
MEM_freeN(locales_menu);
|
||||
}
|
||||
num_locales = num_locales_menu = 0;
|
||||
}
|
||||
|
||||
static void fill_locales(void)
|
||||
{
|
||||
char *languages_path = BLI_get_folder(BLENDER_DATAFILES, "locale");
|
||||
LinkNode *lines = NULL, *line;
|
||||
char *str;
|
||||
int idx = 0;
|
||||
|
||||
free_locales();
|
||||
|
||||
BLI_join_dirfile(languages_path, FILE_MAX, languages_path, "languages");
|
||||
line = lines = BLI_file_read_as_lines(languages_path);
|
||||
|
||||
/* This whole "parsing" code is a bit weak, in that it expects strictly formated input file...
|
||||
* Should not be a problem, though, as this file is script-generated! */
|
||||
|
||||
/* First loop to find highest locale ID */
|
||||
while (line) {
|
||||
int t;
|
||||
str = (char*) line->link;
|
||||
if (str[0] == '#' || str[0] == '\0') {
|
||||
line = line->next;
|
||||
continue; /* Comment or void... */
|
||||
}
|
||||
printf("%s\n", str);
|
||||
t = atoi(str);
|
||||
if (t >= num_locales)
|
||||
num_locales = t + 1;
|
||||
num_locales_menu++;
|
||||
line = line->next;
|
||||
}
|
||||
num_locales_menu++; /* The "closing" void item... */
|
||||
printf("num_locales_menu: %d\n", num_locales_menu);
|
||||
|
||||
/* And now, buil locales and locale_menu! */
|
||||
locales = MEM_callocN(num_locales * sizeof(char*), __func__);
|
||||
locales_menu = MEM_callocN(num_locales_menu * sizeof(EnumPropertyItem), __func__);
|
||||
line = lines;
|
||||
while (line) {
|
||||
int id;
|
||||
char *loc, *sep1, *sep2;
|
||||
|
||||
str = (char*) line->link;
|
||||
if (str[0] == '#' || str[0] == '\0') {
|
||||
line = line->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
id = atoi(str);
|
||||
printf("%s\n", str);
|
||||
sep1 = strchr(str, ':');
|
||||
if (sep1) {
|
||||
sep1++;
|
||||
sep2 = strchr(sep1, ':');
|
||||
if (sep2) {
|
||||
|
||||
locales_menu[idx].value = id;
|
||||
locales_menu[idx].icon = 0;
|
||||
locales_menu[idx].name = BLI_strdupn(sep1, sep2 - sep1);
|
||||
locales_menu[idx].identifier = loc = BLI_strdup(sep2 + 1);
|
||||
if (id == 0) {
|
||||
/* The DEFAULT item... */
|
||||
if (BLI_strnlen(loc, 2))
|
||||
locales[id] = locales_menu[idx].description = BLI_strdup("");
|
||||
/* Menu "label", not to be stored in locales! */
|
||||
else
|
||||
locales_menu[idx].description = BLI_strdup("");
|
||||
}
|
||||
else
|
||||
locales[id] = locales_menu[idx].description = BLI_strdup(loc);
|
||||
idx++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
line = line->next;
|
||||
}
|
||||
|
||||
/* Add closing item to menu! */
|
||||
locales_menu[idx].value = locales_menu[idx].icon = 0;
|
||||
locales_menu[idx].identifier = locales_menu[idx].name = locales_menu[idx].description = "";
|
||||
|
||||
BLI_file_free_lines(lines);
|
||||
}
|
||||
|
||||
EnumPropertyItem *BLF_RNA_lang_enum_properties(void)
|
||||
{
|
||||
return locales_menu;
|
||||
}
|
||||
|
||||
void BLF_lang_init(void)
|
||||
{
|
||||
@@ -117,6 +187,7 @@ void BLF_lang_init(void)
|
||||
|
||||
if (messagepath) {
|
||||
BLI_strncpy(global_messagepath, messagepath, sizeof(global_messagepath));
|
||||
fill_locales();
|
||||
}
|
||||
else {
|
||||
printf("%s: 'locale' data path for translations not found, continuing\n", __func__);
|
||||
@@ -124,6 +195,11 @@ void BLF_lang_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
void BLF_lang_free(void)
|
||||
{
|
||||
free_locales();
|
||||
}
|
||||
|
||||
/* Get LANG/LANGUAGE environment variable. */
|
||||
static void get_language_variable(const char *varname, char *var, const size_t maxlen)
|
||||
{
|
||||
@@ -166,7 +242,8 @@ void BLF_lang_set(const char *str)
|
||||
{
|
||||
char *locreturn;
|
||||
const char *short_locale;
|
||||
int ok = 1;
|
||||
int ok = TRUE;
|
||||
int ulang = ULANGUAGE;
|
||||
|
||||
if ((U.transopts & USER_DOTRANSLATE) == 0)
|
||||
return;
|
||||
@@ -174,14 +251,14 @@ void BLF_lang_set(const char *str)
|
||||
if (str)
|
||||
short_locale = str;
|
||||
else
|
||||
short_locale = locales[2 * U.language + 1];
|
||||
short_locale = LOCALE(ulang);
|
||||
|
||||
#if defined(_WIN32) && !defined(FREE_WINDOWS)
|
||||
{
|
||||
if (short_locale) {
|
||||
char *envStr;
|
||||
|
||||
if (U.language == 0) /* Use system setting. */
|
||||
if (ulang) /* Use system setting. */
|
||||
envStr = BLI_sprintfN("LANG=%s", getenv("LANG"));
|
||||
else
|
||||
envStr = BLI_sprintfN("LANG=%s", short_locale);
|
||||
@@ -196,7 +273,7 @@ void BLF_lang_set(const char *str)
|
||||
if (G.debug & G_DEBUG)
|
||||
printf("Could not change locale to %s\n", short_locale);
|
||||
|
||||
ok = 0;
|
||||
ok = FALSE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -265,7 +342,7 @@ void BLF_lang_set(const char *str)
|
||||
|
||||
locreturn = setlocale(LC_ALL, "");
|
||||
|
||||
ok = 0;
|
||||
ok = FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -284,7 +361,8 @@ void BLF_lang_set(const char *str)
|
||||
|
||||
const char *BLF_lang_get(void)
|
||||
{
|
||||
return locales[2 * U.language + 1];
|
||||
int uilang = ULANGUAGE;
|
||||
return LOCALE(uilang);
|
||||
}
|
||||
|
||||
void BLF_lang_encoding(const char *str)
|
||||
@@ -293,6 +371,9 @@ void BLF_lang_encoding(const char *str)
|
||||
/* bind_textdomain_codeset(TEXT_DOMAIN_NAME, encoding_name); */
|
||||
}
|
||||
|
||||
#undef LOCALE
|
||||
#undef ULANGUAGE
|
||||
|
||||
#else /* ! WITH_INTERNATIONAL */
|
||||
|
||||
void BLF_lang_init(void)
|
||||
@@ -300,6 +381,11 @@ void BLF_lang_init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
void BLF_lang_free(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void BLF_lang_encoding(const char *str)
|
||||
{
|
||||
(void)str;
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_ghash.h"
|
||||
|
||||
#include "BLF_translation.h"
|
||||
|
||||
#include "RNA_define.h"
|
||||
|
||||
#include "rna_internal.h"
|
||||
|
||||
@@ -410,6 +410,13 @@ static EnumPropertyItem *rna_userdef_compute_device_itemf(bContext *UNUSED(C), P
|
||||
}
|
||||
#endif
|
||||
|
||||
static EnumPropertyItem *rna_lang_enum_properties_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr),
|
||||
PropertyRNA *UNUSED(prop), int *free)
|
||||
{
|
||||
*free = 0; /* These items are handled by BLF code! */
|
||||
return BLF_RNA_lang_enum_properties();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna)
|
||||
@@ -2983,6 +2990,7 @@ static void rna_def_userdef_system(BlenderRNA *brna)
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* hardcoded here, could become dynamic somehow */
|
||||
/* locale according to http://www.roseindia.net/tutorials/I18N/locales-list.shtml */
|
||||
/* if you edit here, please also edit the source/blender/blenfont/intern/blf_lang.c 's locales */
|
||||
@@ -3032,6 +3040,12 @@ static void rna_def_userdef_system(BlenderRNA *brna)
|
||||
{30, "TURKISH", 0, "Turkish (Türkçe)", "tr_TR"},
|
||||
{ 0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
#else
|
||||
static EnumPropertyItem language_items[] = {
|
||||
{ 0, "DEFAULT", 0, "Default (Default)", ""},
|
||||
{ 0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef WITH_CYCLES
|
||||
static EnumPropertyItem compute_device_items[] = {
|
||||
@@ -3074,6 +3088,7 @@ static void rna_def_userdef_system(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "language", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, language_items);
|
||||
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_lang_enum_properties_itemf");
|
||||
RNA_def_property_ui_text(prop, "Language", "Language used for translation");
|
||||
RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
|
||||
|
||||
|
||||
@@ -423,6 +423,7 @@ void WM_exit_ext(bContext *C, const short do_python)
|
||||
|
||||
#ifdef WITH_INTERNATIONAL
|
||||
BLF_free_unifont();
|
||||
BLF_lang_free();
|
||||
#endif
|
||||
|
||||
ANIM_keyingset_infos_exit();
|
||||
|
||||
@@ -1064,6 +1064,7 @@ int main(int argc, char** argv)
|
||||
|
||||
#ifdef WITH_INTERNATIONAL
|
||||
BLF_free_unifont();
|
||||
BLF_lang_free();
|
||||
#endif
|
||||
|
||||
IMB_exit();
|
||||
|
||||
Reference in New Issue
Block a user