Простой способ статической языковой интернациализации wanted
От: _hum_ Беларусь  
Дата: 25.10.16 13:18
Оценка:
Чтоб не изобретать велосипед, решил спросить у бывалых, как проще организовать статическую (не предполагающую смены языка в процессе работы проги) интернализацию (в первом приближении, чтоб при компиляции можно было выбирать язык).
Например, если организовывать map, то как хранить ключи — строками или uid-ами (первое нагляднее, второе универсальнее и эффективнее). если uid-ами из enum-в (чтобы нагляднее было), то можно ли избавиться от дублирования его упоминания — при определении uid-а и при его связывании со строкой?
ну и т.п.

Спасибо.
Re: Простой способ статической языковой интернациализации wanted
От: wl. Россия  
Дата: 25.10.16 13:28
Оценка: +1
Здравствуйте, _hum_, Вы писали:

__>Чтоб не изобретать велосипед, решил спросить у бывалых, как проще организовать статическую (не предполагающую смены языка в процессе работы проги) интернализацию (в первом приближении, чтоб при компиляции можно было выбирать язык).

__>Например, если организовывать map, то как хранить ключи — строками или uid-ами (первое нагляднее, второе универсальнее и эффективнее). если uid-ами из enum-в (чтобы нагляднее было), то можно ли избавиться от дублирования его упоминания — при определении uid-а и при его связывании со строкой?
__>ну и т.п.

__>Спасибо.


самый простой способ — отдельные .h файлы с #define MSG_HELLO "hello" / #define MSG_HELLO "Привет"
нужный при компиляции подключается
Re[2]: Простой способ статической языковой интернациализации wanted
От: _hum_ Беларусь  
Дата: 25.10.16 13:30
Оценка:
Здравствуйте, wl., Вы писали:

wl.>Здравствуйте, _hum_, Вы писали:


__>>Чтоб не изобретать велосипед, решил спросить у бывалых, как проще организовать статическую (не предполагающую смены языка в процессе работы проги) интернализацию (в первом приближении, чтоб при компиляции можно было выбирать язык).

__>>Например, если организовывать map, то как хранить ключи — строками или uid-ами (первое нагляднее, второе универсальнее и эффективнее). если uid-ами из enum-в (чтобы нагляднее было), то можно ли избавиться от дублирования его упоминания — при определении uid-а и при его связывании со строкой?
__>>ну и т.п.

__>>Спасибо.


wl.>самый простой способ — отдельные .h файлы с #define MSG_HELLO "hello" / #define MSG_HELLO "Привет"

wl.>нужный при компиляции подключается

а как же засорение пространства и опасность пересечения имен макросов строк с рабочими идентификаторами программы?
Re: Простой способ статической языковой интернациализации wanted
От: AlexGin Беларусь  
Дата: 25.10.16 14:32
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Чтоб не изобретать велосипед, решил спросить у бывалых, как проще организовать статическую (не предполагающую смены языка в процессе работы проги) интернализацию (в первом приближении, чтоб при компиляции можно было выбирать язык).

__>Например, если организовывать map, то как хранить ключи — строками или uid-ами (первое нагляднее, второе универсальнее и эффективнее). если uid-ами из enum-в (чтобы нагляднее было), то можно ли избавиться от дублирования его упоминания — при определении uid-а и при его связывании со строкой?
__>ну и т.п.
Файлы ресурсов: *.rc (STRINGTABLE)
Re[3]: Простой способ статической языковой интернациализации wanted
От: uzhas Ниоткуда  
Дата: 25.10.16 14:54
Оценка:
Здравствуйте, _hum_, Вы писали:

__>а как же засорение пространства и опасность пересечения имен макросов строк с рабочими идентификаторами программы?


не обязательно делать дефайны, можно делать константы
мапу логично делать для горячей смены языка. константы для статики лучше. если же еще надо форматировать текст (ну там подставлять какие-то значения), то лучше выделить функции, которые и будут делать форматирование
Re[4]: Простой способ статической языковой интернациализации wanted
От: _hum_ Беларусь  
Дата: 25.10.16 15:37
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, _hum_, Вы писали:


__>>а как же засорение пространства и опасность пересечения имен макросов строк с рабочими идентификаторами программы?


U>не обязательно делать дефайны, можно делать константы

U>мапу логично делать для горячей смены языка. константы для статики лучше. если же еще надо форматировать текст (ну там подставлять какие-то значения), то лучше выделить функции, которые и будут делать форматирование

константы надо два раза упоминать — при определении и при маппинге
Re[2]: Простой способ статической языковой интернациализации wanted
От: _hum_ Беларусь  
Дата: 25.10.16 15:39
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Здравствуйте, _hum_, Вы писали:


__>>Чтоб не изобретать велосипед, решил спросить у бывалых, как проще организовать статическую (не предполагающую смены языка в процессе работы проги) интернализацию (в первом приближении, чтоб при компиляции можно было выбирать язык).

__>>Например, если организовывать map, то как хранить ключи — строками или uid-ами (первое нагляднее, второе универсальнее и эффективнее). если uid-ами из enum-в (чтобы нагляднее было), то можно ли избавиться от дублирования его упоминания — при определении uid-а и при его связывании со строкой?
__>>ну и т.п.
AG>Файлы ресурсов: *.rc (STRINGTABLE)

это те, что в mfc?
Re[3]: Простой способ статической языковой интернациализации wanted
От: uzhas Ниоткуда  
Дата: 25.10.16 15:56
Оценка:
Здравствуйте, _hum_, Вы писали:

AG>>Файлы ресурсов: *.rc (STRINGTABLE)


__>это те, что в mfc?


оно и без mfc работает. см тут: https://msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx
Re[4]: Простой способ статической языковой интернациализации wanted
От: _hum_ Беларусь  
Дата: 25.10.16 16:10
Оценка:
Здравствуйте, uzhas, Вы писали:

U>Здравствуйте, _hum_, Вы писали:


AG>>>Файлы ресурсов: *.rc (STRINGTABLE)


__>>это те, что в mfc?


U>оно и без mfc работает. см тут: https://msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx


ужас-ужас-ужас (это я не про ваше имя, а про то, что загурзка этих ресурсов до сих пор там под сырым винапи)
Re[5]: Простой способ статической языковой интернациализации wanted
От: _niko_ Россия  
Дата: 26.10.16 19:36
Оценка:
Здравствуйте, _hum_, Вы писали:
__>константы надо два раза упоминать — при определении и при маппинге


  langs\ru-RU.h
LOCALIZATION_ITEM(hello, "Привет")
LOCALIZATION_ITEM(bye,   "Пока")

  langs\en-US.h
LOCALIZATION_ITEM(hello, "Hello")
LOCALIZATION_ITEM(bye,   "Bye")

  langs\current.h
#ifndef LANG_ID
#   define LANG_ID__EN_US 0x0409
#   define LANG_ID__RU_RU 0x0419
#   define LANG_ID LANG_ID__RU_RU
#endif // LANG_ID


#if LANG_ID == LANG_ID__EN_US
#   include "langs\en-US.h"
#elif LANG_ID == LANG_ID__RU_RU
#   include "langs\ru-RU.h"
#endif

  localization.h
#ifndef LOCALIZATION_H
#define LOCALIZATION_H

#include <string>

namespace localization
{
    enum class msg_id
    {
        unknown = 0,

        #define LOCALIZATION_ITEM(id, message) id,
        #include "langs\current.h"
        #undef LOCALIZATION_ITEM
    };

    std::string message(msg_id id);

} // namespace localization

#endif // LOCALIZATION_H

  localization.cpp
#include <exception>

#include "localization.h"

namespace localization
{
    std::string message(msg_id id)
    {
        switch (id)
        {
        case msg_id::unknown:
            return std::string();

        #define LOCALIZATION_ITEM(id, message) case msg_id::id: return std::string(message);
        #include "langs\current.h"
        #undef LOCALIZATION_ITEM

        default:
            throw std::runtime_error("bad msg_id");
        }
    }
    
} // namespace localization

  main.cpp
#include <iostream>

#include "localization.h"

int main(int, char**)
{
    std::cout << localization::message(localization::msg_id::hello) << std::endl;
    std::cout << localization::message(localization::msg_id::bye) << std::endl;

    return 0;
}
Re[6]: Простой способ статической языковой интернациализации
От: _niko_ Россия  
Дата: 26.10.16 20:37
Оценка:
Ну или как то так:
  langs.h
#ifndef LANG_ID
#   define LANG_ID__EN_US 0x0409
#   define LANG_ID__RU_RU 0x0419

#   define LANG_ID LANG_ID__EN_US

#    if LANG_ID == LANG_ID__EN_US
#        define LANGS(msg_en_US, msg_ru_RU) msg_en_US
#    elif LANG_ID == LANG_ID__RU_RU
#        define LANGS(msg_en_US, msg_ru_RU) msg_ru_RU
#    endif
#endif // LANG_ID

LOCALIZATION_ITEM(hello, "Hello", "Привет")
LOCALIZATION_ITEM(bye,   "Bye",   "Пока")

  localization.h
#ifndef LOCALIZATION_H
#define LOCALIZATION_H

#include <string>

namespace localization
{
    enum class msg_id
    {
        unknown = 0,

        #define LOCALIZATION_ITEM(id, ...) id,
        #include "langs.h"
        #undef LOCALIZATION_ITEM
    };

    std::string message(msg_id id);

} // namespace localization

#endif // LOCALIZATION_H

  localization.cpp
#include <exception>

#include "localization.h"

#define LOCALIZATION_ITEM(...)
#include "langs.h"
#undef LOCALIZATION_ITEM


namespace localization
{
    std::string message(msg_id id)
    {
        switch (id)
        {
        case msg_id::unknown:
            return std::string();
        #define LOCALIZATION_ITEM(id, ...) case msg_id::id: return std::string(LANGS(__VA_ARGS__));
        #include "langs.h"
        #undef LOCALIZATION_ITEM

        default:
            throw std::runtime_error("bad msg_id");
        }
    }
    
} // namespace localization

  main.cpp
#include <iostream>

#include "localization.h"

int main(int, char**)
{
    std::cout << localization::message(localization::msg_id::hello) << std::endl;
    std::cout << localization::message(localization::msg_id::bye) << std::endl;

    return 0;
}
Отредактировано 27.10.2016 10:23 _niko_ . Предыдущая версия .
Re: Простой способ статической языковой интернациализации wanted
От: kov_serg Россия  
Дата: 27.10.16 12:55
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Чтоб не изобретать велосипед, решил спросить у бывалых, как проще организовать статическую (не предполагающую смены языка в процессе работы проги) интернализацию (в первом приближении, чтоб при компиляции можно было выбирать язык).

__>Например, если организовывать map, то как хранить ключи — строками или uid-ами (первое нагляднее, второе универсальнее и эффективнее). если uid-ами из enum-в (чтобы нагляднее было), то можно ли избавиться от дублирования его упоминания — при определении uid-а и при его связывании со строкой?
__>ну и т.п.

куда проще?
// Msg.h
#pragma once
struct Msg {
    typedef const char* Strings;
    static Strings
        hello, world;
};

// Msg_EN.cpp
#include "Msg.h"
Msg::Strings
Msg::hello="hello",
Msg::world="world";
Re[7]: Простой способ статической языковой интернациализации
От: _hum_ Беларусь  
Дата: 28.10.16 11:18
Оценка: -3
Здравствуйте, _niko_.
Спасибо, интересный подход, хотя и достаточно технический.
Но я тут, по прошествие времени, пришел к выводу, что выносить все строки в отдельные таблицы — это не совсем удачное решение, поскольку перевод очень сильно зависит от контекста, а потому, по логике, придется еще и как-то информацию о контексте сохранять. Посему, принял решение делать все непосредственно в коде, наподобие:
//////////////////////////////////////////////////////////////////
////           CRepresentationExpertsPool                     ////
//////////////////////////////////////////////////////////////////
class CRepresentationExpertsPool
{
public:
    //.......................................................
    enum class ELanguages{ru_lang,
                          eng_lang};
private:
    static ELanguages s_lang;
public:
    static ELanguages get_lang(void){ return s_lang;}
    static ELanguages set_lang(const ELanguages lang){ s_lang = lang;}
    //-------------------------
    template<typename Res_T>
    static Res_T switch_trsl(Res_T trsl_str)
    {
        return trsl_str; 
    }
    //-------------------------
    template<typename Res_T, typename...Pack>
    static Res_T switch_trsl(const ELanguages lang, Res_T trsl_str,  Pack... TailArg)
    {
        if(get_lang() == lang)return trsl_str;

        return switch_trsl(TailArg...);
    }
    //-------------------------
    //<....>
};
//////////////////////////////////////////////////////////////////


int main()
{
    

    typedef CRepresentationExpertsPool RepPool_T;

    RepPool_T::set_lang(RepPool_T::ELanguages::ru_lang);
    
    std::wstring swButtonText  = 
                        RepPool_T::switch_trsl(RepPool_T::ELanguages::ru_lang,  L"Отмена",
                                               RepPool_T::ELanguages::eng_lang, L"Cancel",
                                               L"??????");
      //<...>
}
Re[2]: Простой способ статической языковой интернациализации wanted
От: _hum_ Беларусь  
Дата: 28.10.16 11:24
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Здравствуйте, _hum_, Вы писали:


__>>Чтоб не изобретать велосипед, решил спросить у бывалых, как проще организовать статическую (не предполагающую смены языка в процессе работы проги) интернализацию (в первом приближении, чтоб при компиляции можно было выбирать язык).

__>>Например, если организовывать map, то как хранить ключи — строками или uid-ами (первое нагляднее, второе универсальнее и эффективнее). если uid-ами из enum-в (чтобы нагляднее было), то можно ли избавиться от дублирования его упоминания — при определении uid-а и при его связывании со строкой?
__>>ну и т.п.

_>куда проще?

_>
_>// Msg.h
_>#pragma once
_>struct Msg {
_>    typedef const char* Strings;
_>    static Strings
_>        hello, world;
_>};

_>// Msg_EN.cpp
_>#include "Msg.h"
_>Msg::Strings
_>Msg::hello="hello",
_>Msg::world="world";
_>


уже же говорил — дубляж кода, и как следствие, необходимость отслеживать синхронизацию (вот затрете случайно инициализацию переменной world и все — потенциально некорректная работа интерфейса (а если это переменная, хранившая надпись для запуска ядерной ракеты, то все может кончиться печально))
Re: Простой способ статической языковой интернациализации wanted
От: bnk СССР http://unmanagedvisio.com/
Дата: 28.10.16 17:51
Оценка: +1
Здравствуйте, _hum_, Вы писали:

__>Чтоб не изобретать велосипед, решил спросить у бывалых, как проще организовать статическую интернализацию.


А стандартный gettxet не подойдёт?
Вроде простой как палка.
Re[8]: Простой способ статической языковой интернациализации
От: andrey.desman  
Дата: 28.10.16 19:06
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Но я тут, по прошествие времени, пришел к выводу, что выносить все строки в отдельные таблицы — это не совсем удачное решение, поскольку перевод очень сильно зависит от контекста, а потому, по логике, придется еще и как-то информацию о контексте сохранять. Посему, принял решение делать все непосредственно в коде, наподобие:


Сколько у тебя кнопок "Отмена"? И как ты относишься к копипасту?
Re[3]: Простой способ статической языковой интернациализации wanted
От: kov_serg Россия  
Дата: 28.10.16 21:37
Оценка:
Здравствуйте, _hum_, Вы писали:

__>Здравствуйте, kov_serg, Вы писали:


_>>Здравствуйте, _hum_, Вы писали:


__>>>Чтоб не изобретать велосипед, решил спросить у бывалых, как проще организовать статическую (не предполагающую смены языка в процессе работы проги) интернализацию (в первом приближении, чтоб при компиляции можно было выбирать язык).

__>>>Например, если организовывать map, то как хранить ключи — строками или uid-ами (первое нагляднее, второе универсальнее и эффективнее). если uid-ами из enum-в (чтобы нагляднее было), то можно ли избавиться от дублирования его упоминания — при определении uid-а и при его связывании со строкой?
__>>>ну и т.п.

_>>куда проще?

_>>
_>>// Msg.h
_>>#pragma once
_>>struct Msg {
_>>    typedef const char* Strings;
_>>    static Strings
_>>        hello, world;
_>>};

_>>// Msg_EN.cpp
_>>#include "Msg.h"
_>>Msg::Strings
_>>Msg::hello="hello",
_>>Msg::world="world";
_>>


__>уже же говорил — дубляж кода, и как следствие, необходимость отслеживать синхронизацию (вот затрете случайно инициализацию переменной world и все — потенциально некорректная работа интерфейса (а если это переменная, хранившая надпись для запуска ядерной ракеты, то все может кончиться печально))


Дублирование кода — а кто вас заставляет это делать руками?
Затрёте инициализаци — нет проблем добавим инициализацию отдельно.
Надёюсь алергии на скриптовые языки нет. Берём какой-нибудь перл:
#!/usr/bin/perl

my $name='Msg';

my $uname=uc($name);
open(my $h1, '>', "$name.h");
open(my $h2, '>', "$name-def.h");
open(my $c1, '>', "$name.cpp");
print $h1 <<TEXT
// $name.h
#pragma once

struct $name {
    typedef const char* Strings;
    static Strings
TEXT
;
print $h1 "\t\t";
print $h2 "// $name-def.h\n\n";
print $c1 <<TEXT
// $name.cpp
#include "$name.h"

#ifndef ${uname}_LANG_FILE
#include "$name-def.h"
#else
#include ${uname}_LANG_FILE
#endif

${name}::Strings
TEXT
;
my $comment="", $nf=0, $idx=0;
while(<DATA>) {
    next if /^\s*(#|$)/;
    my ($nam,$val)=/(\w+)\s+(.*)/; 
    if ($nf) { print $h1 ",$comment\n\t\t"; }
    $idx++;
    print $h1 "$nam"; $comment="\t// $idx - $val";
    my $mn=uc("${name}_$nam");
    print $h2 "#define $mn\t/*$idx*/\"$val\"\n";
    if ($nf) { print $c1 ",\n"; }
    print $c1 "/*$idx*/$name::$nam=$mn";
    $nf=1;
}
print $h1 ";$comment\n};\n\n";
print $c1 ";\n\n";
close $c1;close $h2;close $h1;

__DATA__
# here strings as name value

hello    hello
world    world
text    line1\nline2 \"1\t23\"\n

# comments


После запуска на выходе:
// Msg.h
#pragma once

struct Msg {
    typedef const char* Strings;
    static Strings
        hello,    // 1 - hello
        world,    // 2 - world
        text;    // 3 - line1\nline2 \"1\t23\"\n
};


// Msg.cpp
#include "Msg.h"

#ifndef MSG_LANG_FILE
#include "Msg-def.h"
#else
#include MSG_LANG_FILE
#endif

Msg::Strings
/*1*/Msg::hello=MSG_HELLO,
/*2*/Msg::world=MSG_WORLD,
/*3*/Msg::text=MSG_TEXT;


// Msg-def.h

#define MSG_HELLO    /*1*/"hello"
#define MSG_WORLD    /*2*/"world"
#define MSG_TEXT    /*3*/"line1\nline2 \"1\t23\"\n"


Если какой-то макрос из Msg-def затрёте при переводе компилятор вежливо уматерит.
Re: Простой способ статической языковой интернациализации wanted
От: wander  
Дата: 08.11.16 05:35
Оценка:
Здравствуйте, _hum_.

Не буду говорить, что это просто, или что это обязательно нужно использовать, но как вариант: http://rsdn.org/forum/cpp/6200693.1
Автор: wander
Дата: 02.10.15

Причем смена языка в процессе работы присутствует, но почти не сказывается на производительности.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.