Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Программа с локазизацией. Как можно сделать лучше? 
:(
    Опции темы
exploys
Дата 12.4.2011, 16:05 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 23.4.2009

Репутация: нет
Всего: нет



Делал тестовое задание, что можно было бы сделать лучше или по другому и как вообще делаются подобные приложения с локализациями?
Первое что бы сам изменил это использование namespace. И здесь тоже вопрос как лучше организовать его использование?

Задание:
Код

вводим 10-тичное число цифрами, выводим словами на русском языке в 8-ной и 10-ной системах.

Пример.
Вводим: 131
Выводим:
сто тридцать один в десятичной системе;
двести три в восьмеричной системе.

При проектировании подумайте о том, как ваше решение можно было бы локализовать на английский язык (тут обратите внимание, например, на цифру "двести", которая на английском будет состоять из двух слов).



Код

//---------------------------------------------------------------------------

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <locale>

#include <windows.h>    // для CharToOem в to_rus



#define MAX_TEXT_BUF_SIZE 1024

// Переводы, можно вынести в отдельные файлы
// Русский перевод
#define RUS_RANGE_ERROR "Ошибка диапазона допустимых значений"

#define RUS_0 "ноль"
#define RUS_1 "один"
#define RUS_2    "два"
#define RUS_3 "три"
#define RUS_4 "четыри"
#define RUS_5 "пять"
#define RUS_6 "шесть"
#define RUS_7 "семь"
#define RUS_8 "восемь"
#define RUS_9    "девять"

#define RUS_10 "десять"
#define RUS_11 "одинадцать"
#define RUS_12 "двенадцать"
#define RUS_13 "тринадцать"
#define RUS_14 "четырнадцать"
#define RUS_15 "пятнадцать"
#define RUS_16 "шестнадцать"
#define RUS_17 "семнадцать"
#define RUS_18 "восемнадцать"
#define RUS_19 "девятнадцать"

#define RUS_20 "двадцать"
#define RUS_30 "тридцать"
#define RUS_40 "сорок"
#define RUS_50 "пятьдесят"
#define RUS_60 "шестьдесят"
#define RUS_70 "семьдесят"
#define RUS_80 "восемьдесят"
#define RUS_90 "девяносто"

#define RUS_100 "сто"
#define RUS_200 "двести"
#define RUS_300 "триста"
#define RUS_400 "четыриста"
#define RUS_500 "пятьсот"
#define RUS_600 "шестьсот"
#define RUS_700 "семьсот"
#define RUS_800 "восемьсот"
#define RUS_900 "девятьсот"

//---------------------------------------------------------------------------

// Английский перевод
#define ENG_RANGE_ERROR "Out of range"

#define ENG_0 "zero"
#define ENG_1 "one"
#define ENG_2    "two"
#define ENG_3 "three"
#define ENG_4 "four"
#define ENG_5 "five"
#define ENG_6 "six"
#define ENG_7 "seven"
#define ENG_8 "eight"
#define ENG_9    "nine"

#define ENG_10 "ten"
#define ENG_11 "eleven"
#define ENG_12 "twelve"
#define ENG_13 "thirteen"
#define ENG_14 "fourteen"
#define ENG_15 "fifteen"
#define ENG_16 "sixteen"
#define ENG_17 "seventeen"
#define ENG_18 "eighteen"
#define ENG_19 "nineteen"

#define ENG_20 "twenty"
#define ENG_30 "thirty"
#define ENG_40 "forty"
#define ENG_50 "fifty"
#define ENG_60 "sixty"
#define ENG_70 "seventy"
#define ENG_80 "eighty"
#define ENG_90 "ninety"

#define ENG_100 "hundred"

//---------------------------------------------------------------------------


using namespace std;

// Проверка на 0 в compile-time
// т.к. по условию задачи нельзя использовать BOOST_STATIC_ASSERT
// Специализация для false не объявлена
template < bool > struct CompileTimeChecker;
template <> struct CompileTimeChecker<true>
{
    CompileTimeChecker(...) {};
};

#define STATIC_CHECK( expr ) { sizeof( CompileTimeChecker< (expr) != 0 > ( expr ) ); }



// Базовый класс преобразования числа в строку (Абстрактный)
class TNumber_to_string
{
    public:
    // Конструктор с инициализацией контейнеров
    TNumber_to_string() :digit_10_19(10), first_digit(10),
        second_digit(10),    third_digit(10)
    {
  }

    // В 10-ной системе преобразования числа в строку
    string num_to_str_dec(string const& user_number)
    {
        return num_to_str <10> (user_number);
    }

    // В 8-ной системе преобразования числа в строку
    string num_to_str_oct(string const& user_number)
    {
        return num_to_str <8> (user_number);
    }

    // Шаблон функции для 2-10-ной систем преобразования числа в строку
    // использование шаблона позволит оптимизатору не обращаться
    // к функции dec_to_other_radix<radix> для преобразования в dec
    template<unsigned short radix>
    string num_to_str(string const& user_number)
    {
        string output_string;
        int input_number = atoi(user_number.c_str());

        if (input_number < 0 ||    input_number >= pow(static_cast<double>(radix),3))
            output_string = range_error;
        else
            if (input_number == 0) output_string = zero_num;
        else
        {
            // Преобразование 10-ной в 10-ную не нужно
            if (radix != 10)
                input_number = dec_to_other_radix<radix>(input_number);

            // 3-й знак
            if (input_number > 99)
                output_string += third_digit[get_dig<10>(input_number, 3)] + " ";

            // 2-й знае
            if (input_number % 100 > 19)
                output_string += second_digit[get_dig<10>(input_number, 2)] + " ";

            // 1-й знак и числа 10-19
            if (input_number % 100 > 9 && input_number % 100 < 20)
                output_string += digit_10_19[get_dig<10>(input_number, 1)] + " ";
            else
                output_string += first_digit[get_dig<10>(input_number, 1)];
        }

        return output_string;
    }

    // Шаблон преобразования из 10-ной в систему с основанием radix
    template<unsigned short radix>
    int dec_to_other_radix(int in_num)
    {
        int out_num = 0;
        if (radix == 10) out_num = in_num;
        else
        {
            unsigned int multiplier = 1;
            while (in_num > 0)
            {
                out_num = out_num + (in_num % radix) * multiplier;
                in_num /= radix;
                multiplier *= 10;
            }
        }
        return out_num;

  }

    // Объек класса без языковой локализации создать нельзя
  virtual string cur_language(void) = 0;

    protected:
    // Контейнеры для хранения строк различных локализаций
    vector <string> digit_10_19;
    vector <string> first_digit;
    vector <string> second_digit;
    vector <string> third_digit;
    string zero_num;
    string range_error;

    // Шаблон функции для получения цифры в числе из нужного разряда
    // radix основание системы исчисления
    // шаблон позволяет в compile-time проверить деление на 0
    template<unsigned short radix>
    int get_dig(int user_num, unsigned char const& num_dig)
    {
        STATIC_CHECK(radix);    // Не даст делить на 0 в следующей строке
        user_num /= pow(static_cast<double>(radix),(num_dig-1));
        return user_num % radix;
    }



};

// Русская локализация
class TRus_num_to_str: public TNumber_to_string
{
    public:
    TRus_num_to_str()
    {
        range_error = RUS_RANGE_ERROR;
        zero_num = RUS_0;

        first_digit[0] = "";
        first_digit[1] = RUS_1;
        first_digit[2] = RUS_2;
        first_digit[3] = RUS_3;
        first_digit[4] = RUS_4;
        first_digit[5] = RUS_5;
        first_digit[6] = RUS_6;
        first_digit[7] = RUS_7;
        first_digit[8] = RUS_8;
        first_digit[9] = RUS_9;

        digit_10_19[0] = RUS_10;
        digit_10_19[1] = RUS_11;
        digit_10_19[2] = RUS_12;
        digit_10_19[3] = RUS_13;
        digit_10_19[4] = RUS_14;
        digit_10_19[5] = RUS_15;
        digit_10_19[6] = RUS_16;
        digit_10_19[7] = RUS_17;
        digit_10_19[8] = RUS_18;
        digit_10_19[9] = RUS_19;

        second_digit[1] = RUS_10;
        second_digit[2] = RUS_20;
        second_digit[3] = RUS_30;
        second_digit[4] = RUS_40;
        second_digit[5] = RUS_50;
        second_digit[6] = RUS_60;
        second_digit[7] = RUS_70;
        second_digit[8] = RUS_80;
        second_digit[9] = RUS_90;

        third_digit[1] = RUS_100;
        third_digit[2] = RUS_200;
        third_digit[3] = RUS_300;
        third_digit[4] = RUS_400;
        third_digit[5] = RUS_500;
        third_digit[6] = RUS_600;
        third_digit[7] = RUS_700;
        third_digit[8] = RUS_800;
        third_digit[9] = RUS_900;
    }

    string cur_language(void)
    {
        return "RUS";
    }
};


// Английская локализация
class TEng_num_to_str: public TNumber_to_string
{
    public:
    TEng_num_to_str()
    {
        range_error = ENG_RANGE_ERROR;
        zero_num = ENG_0;

        first_digit[0] = "";
        first_digit[1] = ENG_1;
        first_digit[2] = ENG_2;
        first_digit[3] = ENG_3;
        first_digit[4] = ENG_4;
        first_digit[5] = ENG_5;
        first_digit[6] = ENG_6;
        first_digit[7] = ENG_7;
        first_digit[8] = ENG_8;
        first_digit[9] = ENG_9;

        digit_10_19[0] = ENG_10;
        digit_10_19[1] = ENG_11;
        digit_10_19[2] = ENG_12;
        digit_10_19[3] = ENG_13;
        digit_10_19[4] = ENG_14;
        digit_10_19[5] = ENG_15;
        digit_10_19[6] = ENG_16;
        digit_10_19[7] = ENG_17;
        digit_10_19[8] = ENG_18;
        digit_10_19[9] = ENG_19;

        second_digit[1] = ENG_10;
        second_digit[2] = ENG_20;
        second_digit[3] = ENG_30;
        second_digit[4] = ENG_40;
        second_digit[5] = ENG_50;
        second_digit[6] = ENG_60;
        second_digit[7] = ENG_70;
        second_digit[8] = ENG_80;
        second_digit[9] = ENG_90;

        third_digit[1] = ENG_100;
        third_digit[2] = ENG_2;
        third_digit[3] = ENG_3;
        third_digit[4] = ENG_4;
        third_digit[5] = ENG_5;
        third_digit[6] = ENG_6;
        third_digit[7] = ENG_7;
        third_digit[8] = ENG_8;
        third_digit[9] = ENG_9;
        for (unsigned char iVec = 2; iVec <= 9; iVec++)
        {
            third_digit[iVec] += " ";
            third_digit[iVec] += ENG_100;
        }

    }

    string cur_language(void)
    {
    return "ENG";
  }
};



// Для корректного отображения русских букв
string to_rus(string const& text)
{

    char buf[MAX_TEXT_BUF_SIZE];
    CharToOem(text.c_str(), buf);
    return buf;
}


int _tmain(int argc, _TCHAR* argv[])
{

    setlocale( LC_ALL, "Russian" );
    string user_number, output_string;
    TRus_num_to_str rus_num2str;    // Объект русской локализации
    TEng_num_to_str eng_num2str;    // Объект английской локализации

    cin >> user_number;

    // Русский
    {
        TNumber_to_string &num2str = rus_num2str;
        cout << to_rus(num2str.num_to_str_dec(user_number)) << endl;
        cout << to_rus(num2str.num_to_str_oct(user_number)) << endl;
        cout << num2str.cur_language() << endl;
    }


    // Английский
    {
        TNumber_to_string &num2str = eng_num2str;
        cout << to_rus(num2str.num_to_str_dec(user_number)) << endl;
        cout << to_rus(num2str.num_to_str_oct(user_number)) << endl;
        cout << num2str.cur_language() << endl;
    }

    // Класс без локализации - абстрактный - создать не получится
//  TNumber_to_string num2str;



    system ("PAUSE");


    return 0;
}





PM MAIL   Вверх
bsa
Дата 12.4.2011, 17:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



тебя gettext случаем не устроит?
PM   Вверх
borisbn
Дата 12.4.2011, 21:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



bsa, не понял...

exploys
Цитата(exploys @  12.4.2011,  16:05 Найти цитируемый пост)
Первое что бы сам изменил это использование namespace.

если это единственное, что ты хочешь изменить, то IMHO лучше изменить профессию
Цитата(exploys @  12.4.2011,  16:05 Найти цитируемый пост)

{
    TNumber_to_string &num2str = rus_num2str;
    cout << to_rus(num2str.num_to_str_dec(user_number)) << endl;
    cout << to_rus(num2str.num_to_str_oct(user_number)) << endl;
    cout << num2str.cur_language() << endl;    }
// Английский
{
    TNumber_to_string &num2str = eng_num2str;
    cout << to_rus(num2str.num_to_str_dec(user_number)) << endl;
    cout << to_rus(num2str.num_to_str_oct(user_number)) << endl;
    cout << num2str.cur_language() << endl;
}

а если нужно локализация для 50 языков ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
exploys
Дата 13.4.2011, 22:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 23.4.2009

Репутация: нет
Всего: нет



Цитата(borisbn @ 12.4.2011,  19:11)
bsa, не понял...

exploys
Цитата(exploys @  12.4.2011,  16:05 Найти цитируемый пост)
Первое что бы сам изменил это использование namespace.

если это единственное, что ты хочешь изменить, то IMHO лучше изменить профессию
Цитата(exploys @  12.4.2011,  16:05 Найти цитируемый пост)

{
    TNumber_to_string &num2str = rus_num2str;
    cout << to_rus(num2str.num_to_str_dec(user_number)) << endl;
    cout << to_rus(num2str.num_to_str_oct(user_number)) << endl;
    cout << num2str.cur_language() << endl;    }
// Английский
{
    TNumber_to_string &num2str = eng_num2str;
    cout << to_rus(num2str.num_to_str_dec(user_number)) << endl;
    cout << to_rus(num2str.num_to_str_oct(user_number)) << endl;
    cout << num2str.cur_language() << endl;
}

а если нужно локализация для 50 языков ?

"Первое" и "единственное" разные слова, как по написанию, так и по значению.

По существу, вам не нравится что для каждого языка свой класс? Тогда вопрос почему и как правильно делают?

Добавлено через 1 минуту и 21 секунду
Дополню, что использовать нужно только стандартную библиотеку, т.е. без boost/MFC/VCL etc.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1111 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.