41 #include "table/strings.h"
63 assert(this->
type != NULL);
75 DEBUG(misc, 0,
"Trying to read invalid string parameter");
78 if (this->type != NULL) {
79 assert(this->type[this->
offset] == 0 || this->type[this->
offset] == type);
106 while (max_value >= 10) {
123 uint64 val = count > 1 ? front : next;
124 for (; count > 1; count--) {
125 val = 10 * val + next;
163 GetString(buf,
string,
lastof(buf));
166 for (
int i = 0; i < num; i++) {
168 strings[i] =
stredup((
const char *)(
size_t)_global_string_params.GetParam(i));
169 dst[i] = (size_t)strings[i];
176 static char *StationGetSpecialString(
char *buff,
int x,
const char *last);
177 static char *GetSpecialTownNameString(
char *buff,
int ind, uint32 seed,
const char *last);
178 static char *GetSpecialNameString(
char *buff,
int ind,
StringParameters *args,
const char *last);
180 static char *
FormatString(
char *buff,
const char *str,
StringParameters *args,
const char *last, uint case_index = 0,
bool game_script =
false,
bool dry_run =
false);
186 static char **_langpack_offs;
193 const char *GetStringPtr(
StringID string)
198 case 26: NOT_REACHED();
225 if (index >= 0xC0 && !game_script) {
226 return GetSpecialTownNameString(buffr, index - 0xC0, args->
GetInt32(), last);
231 if (index >= 0xE4 && !game_script) {
232 return GetSpecialNameString(buffr, index - 0xE4, args, last);
239 error(
"Incorrect conversion of custom name string.");
263 error(
"String 0x%X is invalid. You are probably using an old version of the .lng file.\n",
string);
266 return FormatString(buffr, GetStringPtr(
string), args, last, case_index);
269 char *GetString(
char *buffr,
StringID string,
const char *last)
272 _global_string_params.
offset = 0;
307 static char *
FormatNumber(
char *buff, int64 number,
const char *last,
const char *separator,
int zerofill = 1,
int fractional_digits = 0)
309 static const int max_digits = 20;
310 uint64 divisor = 10000000000000000000ULL;
311 zerofill += fractional_digits;
312 int thousands_offset = (max_digits - fractional_digits - 1) % 3;
321 for (
int i = 0; i < max_digits; i++) {
322 if (i == max_digits - fractional_digits) {
325 buff +=
seprintf(buff, last,
"%s", decimal_separator);
329 if (num >= divisor) {
330 quot = num / divisor;
333 if ((tot |= quot) || i >= max_digits - zerofill) {
334 buff +=
seprintf(buff, last,
"%i", (
int)quot);
335 if ((i % 3) == thousands_offset && i < max_digits - 1 - fractional_digits) buff =
strecpy(buff, separator, last);
346 static char *FormatCommaNumber(
char *buff, int64 number,
const char *last,
int fractional_digits = 0)
350 return FormatNumber(buff, number, last, separator, 1, fractional_digits);
353 static char *FormatNoCommaNumber(
char *buff, int64 number,
const char *last)
358 static char *FormatZerofillNumber(
char *buff, int64 number, int64 count,
const char *last)
363 static char *FormatHexNumber(
char *buff, uint64 number,
const char *last)
365 return buff +
seprintf(buff, last,
"0x" OTTD_PRINTFHEX64, number);
375 static char *
FormatBytes(
char *buff, int64 number,
const char *last)
380 const char *
const iec_prefixes[] = {
"",
"Ki",
"Mi",
"Gi",
"Ti",
"Pi",
"Ei"};
382 while (number >= 1024 * 1024) {
392 buff +=
seprintf(buff, last,
"%i", (
int)number);
393 }
else if (number < 1024 * 10) {
394 buff +=
seprintf(buff, last,
"%i%s%02i", (
int)number / 1024, decimal_separator, (
int)(number % 1024) * 100 / 1024);
395 }
else if (number < 1024 * 100) {
396 buff +=
seprintf(buff, last,
"%i%s%01i", (
int)number / 1024, decimal_separator, (
int)(number % 1024) * 10 / 1024);
398 assert(number < 1024 * 1024);
399 buff +=
seprintf(buff, last,
"%i", (
int)number / 1024);
402 assert(
id <
lengthof(iec_prefixes));
403 buff +=
seprintf(buff, last,
NBSP "%sB", iec_prefixes[
id]);
408 static char *FormatYmdString(
char *buff,
Date date,
const char *last, uint case_index)
413 int64 args[] = {ymd.
day + STR_DAY_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.
month, ymd.
year};
415 return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), &tmp_params, last, case_index);
418 static char *FormatMonthAndYear(
char *buff,
Date date,
const char *last, uint case_index)
423 int64 args[] = {STR_MONTH_JAN + ymd.
month, ymd.
year};
425 return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), &tmp_params, last, case_index);
428 static char *FormatTinyOrISODate(
char *buff,
Date date,
StringID str,
const char *last)
439 int64 args[] = {(int64)(
size_t)day, (int64)(
size_t)month, ymd.year};
441 return
FormatString(buff, GetStringPtr(str), &tmp_params, last);
444 static
char *FormatGenericCurrency(
char *buff, const
CurrencySpec *spec,
Money number,
bool compact, const
char *last)
448 bool negative = number < 0;
449 const char *multiplier =
"";
451 number *= spec->rate;
455 if (buff +
Utf8CharLen(SCC_RED) > last)
return buff;
457 buff =
strecpy(buff,
"-", last);
464 if (spec->symbol_pos != 1) buff =
strecpy(buff, spec->prefix, last);
470 if (number >= 1000000000 - 500) {
471 number = (number + 500000) / 1000000;
472 multiplier =
NBSP "M";
473 }
else if (number >= 1000000) {
474 number = (number + 500) / 1000;
475 multiplier =
NBSP "k";
480 if (separator == NULL && !
StrEmpty(_currency->separator)) separator = _currency->separator;
483 buff =
strecpy(buff, multiplier, last);
488 if (spec->symbol_pos != 0) buff =
strecpy(buff, spec->suffix, last);
491 if (buff +
Utf8CharLen(SCC_PREVIOUS_COLOUR) > last)
return buff;
492 buff +=
Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
508 uint64 n =
abs(count);
510 switch (plural_form) {
519 return n != 1 ? 1 : 0;
531 return n > 1 ? 1 : 0;
538 return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
544 return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
550 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
556 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
562 return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
568 return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
574 return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
580 return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
611 return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
616 return ((n == 1 || n == 11) ? 0 : (n == 2 || n == 12) ? 1 : ((n > 2 && n < 11) || (n > 12 && n < 20)) ? 2 : 3);
620 static const char *ParseStringChoice(
const char *b, uint form,
char **dst,
const char *last)
624 uint pos, i, mypos = 0;
626 for (i = pos = 0; i != n; i++) {
627 uint len = (byte)*b++;
628 if (i == form) mypos = pos;
632 *dst +=
seprintf(*dst, last,
"%s", b + mypos);
649 return ((input * this->multiplier) + (round && this->
shift != 0 ? 1 << (this->
shift - 1) : 0)) >> this->
shift;
659 int64
FromDisplay(int64 input,
bool round =
true, int64 divider = 1)
const
661 return ((input << this->
shift) + (round ? (this->multiplier * divider) - 1 : 0)) / (this->multiplier * divider);
680 { { 1, 0}, STR_UNITS_VELOCITY_IMPERIAL },
681 { { 103, 6}, STR_UNITS_VELOCITY_METRIC },
682 { {1831, 12}, STR_UNITS_VELOCITY_SI },
687 { { 1, 0}, STR_UNITS_POWER_IMPERIAL },
688 { {4153, 12}, STR_UNITS_POWER_METRIC },
689 { {6109, 13}, STR_UNITS_POWER_SI },
694 { {4515, 12}, STR_UNITS_WEIGHT_SHORT_IMPERIAL, STR_UNITS_WEIGHT_LONG_IMPERIAL },
695 { { 1, 0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC },
696 { {1000, 0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI },
701 { {4227, 4}, STR_UNITS_VOLUME_SHORT_IMPERIAL, STR_UNITS_VOLUME_LONG_IMPERIAL },
702 { {1000, 0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC },
703 { { 1, 0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI },
708 { {3597, 4}, STR_UNITS_FORCE_IMPERIAL },
709 { {3263, 5}, STR_UNITS_FORCE_METRIC },
710 { { 1, 0}, STR_UNITS_FORCE_SI },
715 { { 3, 0}, STR_UNITS_HEIGHT_IMPERIAL },
716 { { 1, 0}, STR_UNITS_HEIGHT_METRIC },
717 { { 1, 0}, STR_UNITS_HEIGHT_SI },
773 uint orig_offset = args->
offset;
785 FormatString(buff, str_arg, args, last, case_index, game_script,
true);
788 FormatString(buff, str_arg, args, last, case_index, game_script,
true);
791 args->
offset = orig_offset;
794 uint next_substr_case_index = 0;
795 char *buf_start = buff;
796 std::stack<const char *> str_stack;
797 str_stack.push(str_arg);
800 while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) ==
'\0') {
803 if (str_stack.empty())
break;
804 const char *&str = str_stack.top();
810 if (b == 0)
continue;
815 uint64 sub_args_data[20];
816 WChar sub_args_type[20];
817 bool sub_args_need_free[20];
821 memset(sub_args_need_free, 0,
sizeof(sub_args_need_free));
826 stringid = strtol(str, &p, 16);
827 if (*p !=
':' && *p !=
'\0') {
828 while (*p !=
'\0') p++;
830 buff =
strecat(buff,
"(invalid SCC_ENCODED)", last);
834 while (*p !=
'\0') p++;
836 buff =
strecat(buff,
"(invalid StringID)", last);
841 while (*p !=
'\0' && i < 20) {
846 bool instring =
false;
853 if (*p ==
'"' && escape) {
860 instring = !instring;
867 if (*p ==
':')
break;
868 if (*p ==
'\0')
break;
875 bool lookup = (l == SCC_ENCODED);
876 if (lookup) s += len;
878 param = strtoull(s, &p, 16);
882 while (*p !=
'\0') p++;
884 buff =
strecat(buff,
"(invalid sub-StringID)", last);
890 sub_args.SetParam(i++, param);
895 sub_args_need_free[i] =
true;
896 sub_args.SetParam(i++, (uint64)(
size_t)g);
905 for (
int i = 0; i < 20; i++) {
906 if (sub_args_need_free[i])
free((
void *)sub_args.GetParam(i));
912 StringID substr = Utf8Consume(&str);
913 str_stack.push(GetStringPtr(substr));
919 str_stack.push(GetStringPtr(substr));
920 case_index = next_substr_case_index;
921 next_substr_case_index = 0;
926 case SCC_GENDER_LIST: {
928 uint offset = orig_offset + (byte)*str++;
949 WChar c = Utf8Consume(&s);
951 if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
953 str = ParseStringChoice(str, gender, &buff, last);
959 case SCC_GENDER_INDEX:
968 case SCC_PLURAL_LIST: {
969 int plural_form = *str++;
970 uint offset = orig_offset + (byte)*str++;
976 case SCC_ARG_INDEX: {
977 args->
offset = orig_offset + (byte)*str++;
984 next_substr_case_index = (byte)*str++;
988 case SCC_SWITCH_CASE: {
991 uint num = (byte)*str++;
993 if ((byte)str[0] == case_index) {
999 str += 3 + (str[1] << 8) + str[2];
1006 buff =
strecpy(buff, _openttd_revision, last);
1009 case SCC_RAW_STRING_POINTER: {
1010 if (game_script)
break;
1011 const char *str = (
const char *)(
size_t)args->
GetInt64(SCC_RAW_STRING_POINTER);
1023 buff =
GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
1024 next_substr_case_index = 0;
1038 uint size = b - SCC_STRING1 + 1;
1040 buff =
strecat(buff,
"(too many parameters)", last);
1043 buff =
GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
1045 next_substr_case_index = 0;
1050 buff = FormatCommaNumber(buff, args->
GetInt64(SCC_COMMA), last);
1054 int64 number = args->
GetInt64(SCC_DECIMAL);
1055 int digits = args->
GetInt32(SCC_DECIMAL);
1056 buff = FormatCommaNumber(buff, number, last, digits);
1061 buff = FormatNoCommaNumber(buff, args->
GetInt64(SCC_NUM), last);
1064 case SCC_ZEROFILL_NUM: {
1066 buff = FormatZerofillNumber(buff, num, args->
GetInt64(), last);
1071 buff = FormatHexNumber(buff, (uint64)args->
GetInt64(SCC_HEX), last);
1078 case SCC_CARGO_TINY: {
1087 switch (cargo_str) {
1102 buff = FormatCommaNumber(buff, amount, last);
1106 case SCC_CARGO_SHORT: {
1114 switch (cargo_str) {
1140 case SCC_CARGO_LONG: {
1151 case SCC_CARGO_LIST: {
1152 uint32 cmask = args->
GetInt32(SCC_CARGO_LIST);
1159 if (buff >= last - 2)
break;
1173 if (first) buff =
GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
1176 next_substr_case_index = 0;
1179 assert(buff < last);
1183 case SCC_CURRENCY_SHORT:
1184 buff = FormatGenericCurrency(buff, _currency, args->
GetInt64(),
true, last);
1187 case SCC_CURRENCY_LONG:
1188 buff = FormatGenericCurrency(buff, _currency, args->
GetInt64(SCC_CURRENCY_LONG),
false, last);
1192 buff = FormatTinyOrISODate(buff, args->
GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
1195 case SCC_DATE_SHORT:
1196 buff = FormatMonthAndYear(buff, args->
GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
1197 next_substr_case_index = 0;
1201 buff = FormatYmdString(buff, args->
GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
1202 next_substr_case_index = 0;
1206 buff = FormatTinyOrISODate(buff, args->
GetInt32(), STR_FORMAT_DATE_ISO, last);
1233 case SCC_VELOCITY: {
1241 case SCC_VOLUME_SHORT: {
1249 case SCC_VOLUME_LONG: {
1257 case SCC_WEIGHT_SHORT: {
1265 case SCC_WEIGHT_LONG: {
1273 case SCC_COMPANY_NAME: {
1275 if (c == NULL)
break;
1277 if (c->
name != NULL) {
1278 int64 args_array[] = {(int64)(
size_t)c->
name};
1282 int64 args_array[] = {c->
name_2};
1289 case SCC_COMPANY_NUM: {
1294 int64 args_array[] = {company + 1};
1301 case SCC_DEPOT_NAME: {
1304 uint64 args_array[] = {(uint64)args->
GetInt32()};
1305 WChar types_array[] = {SCC_STATION_NAME};
1307 buff =
GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
1312 if (d->name != NULL) {
1313 int64 args_array[] = {(int64)(
size_t)d->name};
1319 buff =
GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->
town_cn == 0 ? 0 : 1), &tmp_params, last);
1324 case SCC_ENGINE_NAME: {
1326 if (e == NULL)
break;
1329 int64 args_array[] = {(int64)(
size_t)e->
name};
1339 case SCC_GROUP_NAME: {
1341 if (g == NULL)
break;
1343 if (g->
name != NULL) {
1344 int64 args_array[] = {(int64)(
size_t)g->
name};
1348 int64 args_array[] = {g->
index};
1356 case SCC_INDUSTRY_NAME: {
1358 if (i == NULL)
break;
1370 buff =
FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
1372 next_substr_case_index = 0;
1376 case SCC_PRESIDENT_NAME: {
1378 if (c == NULL)
break;
1392 case SCC_STATION_NAME: {
1393 StationID sid = args->
GetInt32(SCC_STATION_NAME);
1405 if (st->
name != NULL) {
1406 int64 args_array[] = {(int64)(
size_t)st->
name};
1411 if (st->
indtype != IT_INVALID) {
1423 int64 args_array[] = {STR_TOWN_NAME, st->
town->
index, st->
index};
1430 case SCC_TOWN_NAME: {
1432 if (t == NULL)
break;
1434 if (t->
name != NULL) {
1435 int64 args_array[] = {(int64)(
size_t)t->
name};
1444 case SCC_WAYPOINT_NAME: {
1446 if (wp == NULL)
break;
1448 if (wp->
name != NULL) {
1449 int64 args_array[] = {(int64)(
size_t)wp->
name};
1455 StringID str = ((wp->
string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
1462 case SCC_VEHICLE_NAME: {
1464 if (v == NULL)
break;
1466 if (v->
name != NULL) {
1467 int64 args_array[] = {(int64)(
size_t)v->
name};
1476 default: str = STR_INVALID_VEHICLE;
break;
1477 case VEH_TRAIN: str = STR_SV_TRAIN_NAME;
break;
1478 case VEH_ROAD: str = STR_SV_ROAD_VEHICLE_NAME;
break;
1479 case VEH_SHIP: str = STR_SV_SHIP_NAME;
break;
1488 case SCC_SIGN_NAME: {
1490 if (si == NULL)
break;
1492 if (si->name != NULL) {
1493 int64 args_array[] = {(int64)(
size_t)si->name};
1503 case SCC_STATION_FEATURES: {
1504 buff = StationGetSpecialString(buff, args->
GetInt32(SCC_STATION_FEATURES), last);
1518 static char *StationGetSpecialString(
char *buff,
int x,
const char *last)
1529 static char *GetSpecialTownNameString(
char *buff,
int ind, uint32 seed,
const char *last)
1534 static const char *
const _silly_company_names[] = {
1536 "Tiny Transport Ltd.",
1538 "Comfy-Coach & Co.",
1539 "Crush & Bump Ltd.",
1540 "Broken & Late Ltd.",
1542 "Supersonic Travel",
1544 "Lightning International",
1545 "Pannik & Loozit Ltd.",
1546 "Inter-City Transport",
1547 "Getout & Pushit Ltd."
1550 static const char *
const _surname_list[] = {
1582 static const char *
const _silly_surname_list[] = {
1597 static const char _initial_name_letters[] = {
1598 'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
1599 'K',
'L',
'M',
'N',
'P',
'R',
'S',
'T',
'W',
1602 static char *GenAndCoName(
char *buff, uint32 arg,
const char *last)
1604 const char *
const *base;
1608 base = _silly_surname_list;
1609 num =
lengthof(_silly_surname_list);
1611 base = _surname_list;
1615 buff =
strecpy(buff, base[num *
GB(arg, 16, 8) >> 8], last);
1616 buff =
strecpy(buff,
" & Co.", last);
1621 static char *GenPresidentName(
char *buff, uint32 x,
const char *last)
1623 char initial[] =
"?. ";
1624 const char *
const *base;
1628 initial[0] = _initial_name_letters[
sizeof(_initial_name_letters) *
GB(x, 0, 8) >> 8];
1629 buff =
strecpy(buff, initial, last);
1631 i = (
sizeof(_initial_name_letters) + 35) *
GB(x, 8, 8) >> 8;
1632 if (i <
sizeof(_initial_name_letters)) {
1633 initial[0] = _initial_name_letters[i];
1634 buff =
strecpy(buff, initial, last);
1638 base = _silly_surname_list;
1639 num =
lengthof(_silly_surname_list);
1641 base = _surname_list;
1645 buff =
strecpy(buff, base[num *
GB(x, 16, 8) >> 8], last);
1650 static char *GetSpecialNameString(
char *buff,
int ind,
StringParameters *args,
const char *last)
1657 return GenAndCoName(buff, args->
GetInt32(), last);
1660 return GenPresidentName(buff, args->
GetInt32(), last);
1664 if (
IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
1665 buff = GetSpecialTownNameString(buff, ind - 6, args->
GetInt32(), last);
1666 return strecpy(buff,
" Transport", last);
1670 if (
IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
1671 int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
1673 &_languages[i] == _current_language ? _current_language->
own_name : _languages[i].name, last);
1677 if (
IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
1678 int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
1688 #ifdef ENABLE_NETWORK
1689 extern void SortNetworkLanguages();
1691 static inline void SortNetworkLanguages() {}
1701 this->
version == TO_LE32(LANGUAGE_PACK_VERSION) &&
1725 if (lang_pack == NULL)
return false;
1728 const char *end = (
char *)lang_pack + len + 1;
1731 if (end <= lang_pack->data || !lang_pack->
IsValid()) {
1736 #if TTD_ENDIAN == TTD_BIG_ENDIAN
1744 uint16 num = lang_pack->
offsets[i];
1756 char **langpack_offs = MallocT<char *>(count);
1759 char *s = lang_pack->data;
1761 for (uint i = 0; i < count; i++) {
1762 if (s + len >= end) {
1764 free(langpack_offs);
1768 len = ((len & 0x3F) << 8) + (byte)*s++;
1769 if (s + len >= end) {
1771 free(langpack_offs);
1775 langpack_offs[i] = s;
1782 _langpack = lang_pack;
1784 free(_langpack_offs);
1785 _langpack_offs = langpack_offs;
1787 _current_language = lang;
1789 const char *c_file = strrchr(_current_language->
file, PATHSEPCHAR) + 1;
1793 #ifdef WITH_ICU_SORT
1801 UErrorCode status = U_ZERO_ERROR;
1806 if (U_FAILURE(status)) {
1817 SortNetworkLanguages();
1832 #if !(defined(WIN32) || defined(__APPLE__))
1845 env = getenv(
"LANGUAGE");
1846 if (env != NULL)
return env;
1848 env = getenv(
"LC_ALL");
1849 if (env != NULL)
return env;
1851 if (param != NULL) {
1852 env = getenv(param);
1853 if (env != NULL)
return env;
1856 return getenv(
"LANG");
1866 GetString(stra, *a,
lastof(stra));
1867 GetString(strb, *b,
lastof(strb));
1880 if (newgrflangid == lang->newgrflangid)
return lang;
1894 FILE *f = fopen(file,
"rb");
1895 if (f == NULL)
return false;
1897 size_t read = fread(hdr,
sizeof(*hdr), 1, f);
1900 bool ret = read == 1 && hdr->
IsValid();
1918 struct dirent *dirent;
1919 while ((dirent = readdir(dir)) != NULL) {
1920 const char *d_name =
FS2OTTD(dirent->d_name);
1921 const char *extension = strrchr(d_name,
'.');
1924 if (extension == NULL || strcmp(extension,
".lng") != 0)
continue;
1931 DEBUG(misc, 3,
"%s is not a valid language file", lmd.
file);
1933 DEBUG(misc, 3,
"%s's language ID is already known", lmd.
file);
1935 *_languages.
Append() = lmd;
1951 char path[MAX_PATH];
1955 if (_languages.
Length() == 0)
usererror(
"No available language packs (invalid versions?)");
1959 if (lang == NULL) lang =
"en_GB";
1970 const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
1972 chosen_language = lng;
1976 if (strcmp (lng->isocode,
"en_GB") == 0) en_GB_fallback = lng;
1977 if (strncmp(lng->isocode, lang, 5) == 0) chosen_language = lng;
1978 if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
1983 if (chosen_language == NULL) {
1984 chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
2008 const Sprite *question_mark[FS_END];
2011 question_mark[size] =
GetGlyph(size,
'?');
2017 if (str != NULL) *str = text;
2018 for (
WChar c = Utf8Consume(&text); c !=
'\0'; c = Utf8Consume(&text)) {
2048 const char *NextString()
2055 while (this->i < TAB_COUNT && this->
j >=
_langtab_num[this->i]) {
2070 #ifdef WITH_FREETYPE
2094 if (searcher == NULL) searcher = &pack_searcher;
2096 #ifdef WITH_FREETYPE
2101 memcpy(&backup, &_freetype,
sizeof(backup));
2105 memcpy(&_freetype, &backup,
sizeof(backup));
2107 if (bad_font && base_font) {
2122 static char *err_str =
stredup(
"XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this.");
2135 #if !defined(WITH_ICU_LAYOUT)
2150 static char *err_str =
stredup(
"XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");