43 #include "table/strings.h"
65 assert(this->
type != NULL);
77 DEBUG(misc, 0,
"Trying to read invalid string parameter");
80 if (this->type != NULL) {
81 assert(this->type[this->
offset] == 0 || this->type[this->
offset] == type);
108 while (max_value >= 10) {
125 uint64 val = count > 1 ? front : next;
126 for (; count > 1; count--) {
127 val = 10 * val + next;
165 GetString(buf,
string,
lastof(buf));
168 for (
int i = 0; i < num; i++) {
170 strings[i] =
stredup((
const char *)(
size_t)_global_string_params.GetParam(i));
171 dst[i] = (size_t)strings[i];
178 static char *StationGetSpecialString(
char *buff,
int x,
const char *last);
179 static char *GetSpecialTownNameString(
char *buff,
int ind, uint32 seed,
const char *last);
180 static char *GetSpecialNameString(
char *buff,
int ind,
StringParameters *args,
const char *last);
182 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);
188 static char **_langpack_offs;
195 const char *GetStringPtr(
StringID string)
200 case 26: NOT_REACHED();
227 if (index >= 0xC0 && !game_script) {
228 return GetSpecialTownNameString(buffr, index - 0xC0, args->
GetInt32(), last);
233 if (index >= 0xE4 && !game_script) {
234 return GetSpecialNameString(buffr, index - 0xE4, args, last);
241 error(
"Incorrect conversion of custom name string.");
265 error(
"String 0x%X is invalid. You are probably using an old version of the .lng file.\n",
string);
268 return FormatString(buffr, GetStringPtr(
string), args, last, case_index);
271 char *GetString(
char *buffr,
StringID string,
const char *last)
274 _global_string_params.
offset = 0;
309 static char *
FormatNumber(
char *buff, int64 number,
const char *last,
const char *separator,
int zerofill = 1,
int fractional_digits = 0)
311 static const int max_digits = 20;
312 uint64 divisor = 10000000000000000000ULL;
313 zerofill += fractional_digits;
314 int thousands_offset = (max_digits - fractional_digits - 1) % 3;
323 for (
int i = 0; i < max_digits; i++) {
324 if (i == max_digits - fractional_digits) {
327 buff +=
seprintf(buff, last,
"%s", decimal_separator);
331 if (num >= divisor) {
332 quot = num / divisor;
335 if ((tot |= quot) || i >= max_digits - zerofill) {
336 buff +=
seprintf(buff, last,
"%i", (
int)quot);
337 if ((i % 3) == thousands_offset && i < max_digits - 1 - fractional_digits) buff =
strecpy(buff, separator, last);
348 static char *FormatCommaNumber(
char *buff, int64 number,
const char *last,
int fractional_digits = 0)
352 return FormatNumber(buff, number, last, separator, 1, fractional_digits);
355 static char *FormatNoCommaNumber(
char *buff, int64 number,
const char *last)
360 static char *FormatZerofillNumber(
char *buff, int64 number, int64 count,
const char *last)
365 static char *FormatHexNumber(
char *buff, uint64 number,
const char *last)
367 return buff +
seprintf(buff, last,
"0x" OTTD_PRINTFHEX64, number);
377 static char *
FormatBytes(
char *buff, int64 number,
const char *last)
382 const char *
const iec_prefixes[] = {
"",
"Ki",
"Mi",
"Gi",
"Ti",
"Pi",
"Ei"};
384 while (number >= 1024 * 1024) {
394 buff +=
seprintf(buff, last,
"%i", (
int)number);
395 }
else if (number < 1024 * 10) {
396 buff +=
seprintf(buff, last,
"%i%s%02i", (
int)number / 1024, decimal_separator, (
int)(number % 1024) * 100 / 1024);
397 }
else if (number < 1024 * 100) {
398 buff +=
seprintf(buff, last,
"%i%s%01i", (
int)number / 1024, decimal_separator, (
int)(number % 1024) * 10 / 1024);
400 assert(number < 1024 * 1024);
401 buff +=
seprintf(buff, last,
"%i", (
int)number / 1024);
404 assert(
id <
lengthof(iec_prefixes));
405 buff +=
seprintf(buff, last,
NBSP "%sB", iec_prefixes[
id]);
410 static char *FormatYmdString(
char *buff,
Date date,
const char *last, uint case_index)
415 int64 args[] = {ymd.
day + STR_DAY_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.
month, ymd.
year};
417 return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), &tmp_params, last, case_index);
420 static char *FormatMonthAndYear(
char *buff,
Date date,
const char *last, uint case_index)
425 int64 args[] = {STR_MONTH_JAN + ymd.
month, ymd.
year};
427 return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), &tmp_params, last, case_index);
430 static char *FormatTinyOrISODate(
char *buff,
Date date,
StringID str,
const char *last)
441 int64 args[] = {(int64)(
size_t)day, (int64)(
size_t)month, ymd.year};
443 return
FormatString(buff, GetStringPtr(str), &tmp_params, last);
446 static
char *FormatGenericCurrency(
char *buff, const
CurrencySpec *spec,
Money number,
bool compact, const
char *last)
450 bool negative = number < 0;
451 const char *multiplier =
"";
453 number *= spec->rate;
457 if (buff +
Utf8CharLen(SCC_RED) > last)
return buff;
459 buff =
strecpy(buff,
"-", last);
466 if (spec->symbol_pos != 1) buff =
strecpy(buff, spec->prefix, last);
472 if (number >= 1000000000 - 500) {
473 number = (number + 500000) / 1000000;
474 multiplier =
NBSP "M";
475 }
else if (number >= 1000000) {
476 number = (number + 500) / 1000;
477 multiplier =
NBSP "k";
482 if (separator == NULL && !
StrEmpty(_currency->separator)) separator = _currency->separator;
485 buff =
strecpy(buff, multiplier, last);
490 if (spec->symbol_pos != 0) buff =
strecpy(buff, spec->suffix, last);
493 if (buff +
Utf8CharLen(SCC_PREVIOUS_COLOUR) > last)
return buff;
494 buff +=
Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
510 uint64 n =
abs(count);
512 switch (plural_form) {
521 return n != 1 ? 1 : 0;
533 return n > 1 ? 1 : 0;
540 return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2;
546 return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4;
552 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
558 return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
564 return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
570 return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3;
576 return n % 10 == 1 && n % 100 != 11 ? 0 : 1;
582 return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2;
613 return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3);
618 return ((n == 1 || n == 11) ? 0 : (n == 2 || n == 12) ? 1 : ((n > 2 && n < 11) || (n > 12 && n < 20)) ? 2 : 3);
622 static const char *ParseStringChoice(
const char *b, uint form,
char **dst,
const char *last)
626 uint pos, i, mypos = 0;
628 for (i = pos = 0; i != n; i++) {
629 uint len = (byte)*b++;
630 if (i == form) mypos = pos;
634 *dst +=
seprintf(*dst, last,
"%s", b + mypos);
651 return ((input * this->multiplier) + (round && this->
shift != 0 ? 1 << (this->
shift - 1) : 0)) >> this->
shift;
661 int64
FromDisplay(int64 input,
bool round =
true, int64 divider = 1)
const
663 return ((input << this->
shift) + (round ? (this->multiplier * divider) - 1 : 0)) / (this->multiplier * divider);
682 { { 1, 0}, STR_UNITS_VELOCITY_IMPERIAL },
683 { { 103, 6}, STR_UNITS_VELOCITY_METRIC },
684 { {1831, 12}, STR_UNITS_VELOCITY_SI },
689 { { 1, 0}, STR_UNITS_POWER_IMPERIAL },
690 { {4153, 12}, STR_UNITS_POWER_METRIC },
691 { {6109, 13}, STR_UNITS_POWER_SI },
696 { {4515, 12}, STR_UNITS_WEIGHT_SHORT_IMPERIAL, STR_UNITS_WEIGHT_LONG_IMPERIAL },
697 { { 1, 0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC },
698 { {1000, 0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI },
703 { {4227, 4}, STR_UNITS_VOLUME_SHORT_IMPERIAL, STR_UNITS_VOLUME_LONG_IMPERIAL },
704 { {1000, 0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC },
705 { { 1, 0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI },
710 { {3597, 4}, STR_UNITS_FORCE_IMPERIAL },
711 { {3263, 5}, STR_UNITS_FORCE_METRIC },
712 { { 1, 0}, STR_UNITS_FORCE_SI },
717 { { 3, 0}, STR_UNITS_HEIGHT_IMPERIAL },
718 { { 1, 0}, STR_UNITS_HEIGHT_METRIC },
719 { { 1, 0}, STR_UNITS_HEIGHT_SI },
775 uint orig_offset = args->
offset;
787 FormatString(buff, str_arg, args, last, case_index, game_script,
true);
790 FormatString(buff, str_arg, args, last, case_index, game_script,
true);
793 args->
offset = orig_offset;
796 uint next_substr_case_index = 0;
797 char *buf_start = buff;
798 std::stack<const char *> str_stack;
799 str_stack.push(str_arg);
802 while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) ==
'\0') {
805 if (str_stack.empty())
break;
806 const char *&str = str_stack.top();
812 if (b == 0)
continue;
817 uint64 sub_args_data[20];
818 WChar sub_args_type[20];
819 bool sub_args_need_free[20];
823 memset(sub_args_need_free, 0,
sizeof(sub_args_need_free));
828 stringid = strtol(str, &p, 16);
829 if (*p !=
':' && *p !=
'\0') {
830 while (*p !=
'\0') p++;
832 buff =
strecat(buff,
"(invalid SCC_ENCODED)", last);
836 while (*p !=
'\0') p++;
838 buff =
strecat(buff,
"(invalid StringID)", last);
843 while (*p !=
'\0' && i < 20) {
848 bool instring =
false;
855 if (*p ==
'"' && escape) {
862 instring = !instring;
869 if (*p ==
':')
break;
870 if (*p ==
'\0')
break;
877 bool lookup = (l == SCC_ENCODED);
878 if (lookup) s += len;
880 param = strtoull(s, &p, 16);
884 while (*p !=
'\0') p++;
886 buff =
strecat(buff,
"(invalid sub-StringID)", last);
892 sub_args.SetParam(i++, param);
897 sub_args_need_free[i] =
true;
898 sub_args.SetParam(i++, (uint64)(
size_t)g);
907 for (
int i = 0; i < 20; i++) {
908 if (sub_args_need_free[i])
free((
void *)sub_args.GetParam(i));
914 StringID substr = Utf8Consume(&str);
915 str_stack.push(GetStringPtr(substr));
921 str_stack.push(GetStringPtr(substr));
922 case_index = next_substr_case_index;
923 next_substr_case_index = 0;
928 case SCC_GENDER_LIST: {
930 uint offset = orig_offset + (byte)*str++;
951 WChar c = Utf8Consume(&s);
953 if (c == SCC_GENDER_INDEX) gender = (byte)s[0];
955 str = ParseStringChoice(str, gender, &buff, last);
961 case SCC_GENDER_INDEX:
970 case SCC_PLURAL_LIST: {
971 int plural_form = *str++;
972 uint offset = orig_offset + (byte)*str++;
978 case SCC_ARG_INDEX: {
979 args->
offset = orig_offset + (byte)*str++;
986 next_substr_case_index = (byte)*str++;
990 case SCC_SWITCH_CASE: {
993 uint num = (byte)*str++;
995 if ((byte)str[0] == case_index) {
1001 str += 3 + (str[1] << 8) + str[2];
1008 buff =
strecpy(buff, _openttd_revision, last);
1011 case SCC_RAW_STRING_POINTER: {
1012 if (game_script)
break;
1013 const char *str = (
const char *)(
size_t)args->
GetInt64(SCC_RAW_STRING_POINTER);
1025 buff =
GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script);
1026 next_substr_case_index = 0;
1040 uint size = b - SCC_STRING1 + 1;
1042 buff =
strecat(buff,
"(too many parameters)", last);
1045 buff =
GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script);
1047 next_substr_case_index = 0;
1052 buff = FormatCommaNumber(buff, args->
GetInt64(SCC_COMMA), last);
1056 int64 number = args->
GetInt64(SCC_DECIMAL);
1057 int digits = args->
GetInt32(SCC_DECIMAL);
1058 buff = FormatCommaNumber(buff, number, last, digits);
1063 buff = FormatNoCommaNumber(buff, args->
GetInt64(SCC_NUM), last);
1066 case SCC_ZEROFILL_NUM: {
1068 buff = FormatZerofillNumber(buff, num, args->
GetInt64(), last);
1073 buff = FormatHexNumber(buff, (uint64)args->
GetInt64(SCC_HEX), last);
1080 case SCC_CARGO_TINY: {
1089 switch (cargo_str) {
1104 buff = FormatCommaNumber(buff, amount, last);
1108 case SCC_CARGO_SHORT: {
1116 switch (cargo_str) {
1142 case SCC_CARGO_LONG: {
1153 case SCC_CARGO_LIST: {
1154 uint32 cmask = args->
GetInt32(SCC_CARGO_LIST);
1161 if (buff >= last - 2)
break;
1175 if (first) buff =
GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script);
1178 next_substr_case_index = 0;
1181 assert(buff < last);
1185 case SCC_CURRENCY_SHORT:
1186 buff = FormatGenericCurrency(buff, _currency, args->
GetInt64(),
true, last);
1189 case SCC_CURRENCY_LONG:
1190 buff = FormatGenericCurrency(buff, _currency, args->
GetInt64(SCC_CURRENCY_LONG),
false, last);
1194 buff = FormatTinyOrISODate(buff, args->
GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last);
1197 case SCC_DATE_SHORT:
1198 buff = FormatMonthAndYear(buff, args->
GetInt32(SCC_DATE_SHORT), last, next_substr_case_index);
1199 next_substr_case_index = 0;
1203 buff = FormatYmdString(buff, args->
GetInt32(SCC_DATE_LONG), last, next_substr_case_index);
1204 next_substr_case_index = 0;
1208 buff = FormatTinyOrISODate(buff, args->
GetInt32(), STR_FORMAT_DATE_ISO, last);
1235 case SCC_VELOCITY: {
1243 case SCC_VOLUME_SHORT: {
1251 case SCC_VOLUME_LONG: {
1259 case SCC_WEIGHT_SHORT: {
1267 case SCC_WEIGHT_LONG: {
1275 case SCC_COMPANY_NAME: {
1277 if (c == NULL)
break;
1279 if (c->
name != NULL) {
1280 int64 args_array[] = {(int64)(
size_t)c->
name};
1284 int64 args_array[] = {c->
name_2};
1291 case SCC_COMPANY_NUM: {
1296 int64 args_array[] = {company + 1};
1303 case SCC_DEPOT_NAME: {
1306 uint64 args_array[] = {(uint64)args->
GetInt32()};
1307 WChar types_array[] = {SCC_STATION_NAME};
1309 buff =
GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last);
1314 if (d->name != NULL) {
1315 int64 args_array[] = {(int64)(
size_t)d->name};
1321 buff =
GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->
town_cn == 0 ? 0 : 1), &tmp_params, last);
1326 case SCC_ENGINE_NAME: {
1328 if (e == NULL)
break;
1331 int64 args_array[] = {(int64)(
size_t)e->
name};
1341 case SCC_GROUP_NAME: {
1343 if (g == NULL)
break;
1345 if (g->
name != NULL) {
1346 int64 args_array[] = {(int64)(
size_t)g->
name};
1350 int64 args_array[] = {g->
index};
1358 case SCC_INDUSTRY_NAME: {
1360 if (i == NULL)
break;
1372 buff =
FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index);
1374 next_substr_case_index = 0;
1378 case SCC_PRESIDENT_NAME: {
1380 if (c == NULL)
break;
1394 case SCC_STATION_NAME: {
1395 StationID sid = args->
GetInt32(SCC_STATION_NAME);
1407 if (st->
name != NULL) {
1408 int64 args_array[] = {(int64)(
size_t)st->
name};
1413 if (st->
indtype != IT_INVALID) {
1425 int64 args_array[] = {STR_TOWN_NAME, st->
town->
index, st->
index};
1432 case SCC_TOWN_NAME: {
1434 if (t == NULL)
break;
1436 if (t->
name != NULL) {
1437 int64 args_array[] = {(int64)(
size_t)t->
name};
1446 case SCC_WAYPOINT_NAME: {
1448 if (wp == NULL)
break;
1450 if (wp->
name != NULL) {
1451 int64 args_array[] = {(int64)(
size_t)wp->
name};
1457 StringID str = ((wp->
string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME);
1464 case SCC_VEHICLE_NAME: {
1466 if (v == NULL)
break;
1468 if (v->
name != NULL) {
1469 int64 args_array[] = {(int64)(
size_t)v->
name};
1478 default: str = STR_INVALID_VEHICLE;
break;
1479 case VEH_TRAIN: str = STR_SV_TRAIN_NAME;
break;
1480 case VEH_ROAD: str = STR_SV_ROAD_VEHICLE_NAME;
break;
1481 case VEH_SHIP: str = STR_SV_SHIP_NAME;
break;
1490 case SCC_SIGN_NAME: {
1492 if (si == NULL)
break;
1494 if (si->name != NULL) {
1495 int64 args_array[] = {(int64)(
size_t)si->name};
1505 case SCC_STATION_FEATURES: {
1506 buff = StationGetSpecialString(buff, args->
GetInt32(SCC_STATION_FEATURES), last);
1520 static char *StationGetSpecialString(
char *buff,
int x,
const char *last)
1531 static char *GetSpecialTownNameString(
char *buff,
int ind, uint32 seed,
const char *last)
1536 static const char *
const _silly_company_names[] = {
1538 "Tiny Transport Ltd.",
1540 "Comfy-Coach & Co.",
1541 "Crush & Bump Ltd.",
1542 "Broken & Late Ltd.",
1544 "Supersonic Travel",
1546 "Lightning International",
1547 "Pannik & Loozit Ltd.",
1548 "Inter-City Transport",
1549 "Getout & Pushit Ltd."
1552 static const char *
const _surname_list[] = {
1584 static const char *
const _silly_surname_list[] = {
1599 static const char _initial_name_letters[] = {
1600 'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
1601 'K',
'L',
'M',
'N',
'P',
'R',
'S',
'T',
'W',
1604 static char *GenAndCoName(
char *buff, uint32 arg,
const char *last)
1606 const char *
const *base;
1610 base = _silly_surname_list;
1611 num =
lengthof(_silly_surname_list);
1613 base = _surname_list;
1617 buff =
strecpy(buff, base[num *
GB(arg, 16, 8) >> 8], last);
1618 buff =
strecpy(buff,
" & Co.", last);
1623 static char *GenPresidentName(
char *buff, uint32 x,
const char *last)
1625 char initial[] =
"?. ";
1626 const char *
const *base;
1630 initial[0] = _initial_name_letters[
sizeof(_initial_name_letters) *
GB(x, 0, 8) >> 8];
1631 buff =
strecpy(buff, initial, last);
1633 i = (
sizeof(_initial_name_letters) + 35) *
GB(x, 8, 8) >> 8;
1634 if (i <
sizeof(_initial_name_letters)) {
1635 initial[0] = _initial_name_letters[i];
1636 buff =
strecpy(buff, initial, last);
1640 base = _silly_surname_list;
1641 num =
lengthof(_silly_surname_list);
1643 base = _surname_list;
1647 buff =
strecpy(buff, base[num *
GB(x, 16, 8) >> 8], last);
1652 static char *GetSpecialNameString(
char *buff,
int ind,
StringParameters *args,
const char *last)
1659 return GenAndCoName(buff, args->
GetInt32(), last);
1662 return GenPresidentName(buff, args->
GetInt32(), last);
1666 if (
IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) {
1667 buff = GetSpecialTownNameString(buff, ind - 6, args->
GetInt32(), last);
1668 return strecpy(buff,
" Transport", last);
1672 if (
IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) {
1673 int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4);
1675 &_languages[i] == _current_language ? _current_language->
own_name : _languages[i].name, last);
1679 if (
IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) {
1680 int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4);
1690 #ifdef ENABLE_NETWORK
1691 extern void SortNetworkLanguages();
1693 static inline void SortNetworkLanguages() {}
1703 this->
version == TO_LE32(LANGUAGE_PACK_VERSION) &&
1727 if (lang_pack == NULL)
return false;
1730 const char *end = (
char *)lang_pack + len + 1;
1733 if (end <= lang_pack->data || !lang_pack->
IsValid()) {
1738 #if TTD_ENDIAN == TTD_BIG_ENDIAN
1746 uint16 num = lang_pack->
offsets[i];
1758 char **langpack_offs = MallocT<char *>(count);
1761 char *s = lang_pack->data;
1763 for (uint i = 0; i < count; i++) {
1764 if (s + len >= end) {
1766 free(langpack_offs);
1770 len = ((len & 0x3F) << 8) + (byte)*s++;
1771 if (s + len >= end) {
1773 free(langpack_offs);
1777 langpack_offs[i] = s;
1784 _langpack = lang_pack;
1786 free(_langpack_offs);
1787 _langpack_offs = langpack_offs;
1789 _current_language = lang;
1791 const char *c_file = strrchr(_current_language->
file, PATHSEPCHAR) + 1;
1795 #ifdef WITH_ICU_SORT
1803 UErrorCode status = U_ZERO_ERROR;
1808 if (U_FAILURE(status)) {
1819 SortNetworkLanguages();
1820 #ifdef ENABLE_NETWORK
1836 #if !(defined(WIN32) || defined(__APPLE__))
1849 env = getenv(
"LANGUAGE");
1850 if (env != NULL)
return env;
1852 env = getenv(
"LC_ALL");
1853 if (env != NULL)
return env;
1855 if (param != NULL) {
1856 env = getenv(param);
1857 if (env != NULL)
return env;
1860 return getenv(
"LANG");
1870 GetString(stra, *a,
lastof(stra));
1871 GetString(strb, *b,
lastof(strb));
1884 if (newgrflangid == lang->newgrflangid)
return lang;
1898 FILE *f = fopen(file,
"rb");
1899 if (f == NULL)
return false;
1901 size_t read = fread(hdr,
sizeof(*hdr), 1, f);
1904 bool ret = read == 1 && hdr->
IsValid();
1922 struct dirent *dirent;
1923 while ((dirent = readdir(dir)) != NULL) {
1924 const char *d_name =
FS2OTTD(dirent->d_name);
1925 const char *extension = strrchr(d_name,
'.');
1928 if (extension == NULL || strcmp(extension,
".lng") != 0)
continue;
1935 DEBUG(misc, 3,
"%s is not a valid language file", lmd.
file);
1937 DEBUG(misc, 3,
"%s's language ID is already known", lmd.
file);
1939 *_languages.
Append() = lmd;
1955 char path[MAX_PATH];
1959 if (_languages.
Length() == 0)
usererror(
"No available language packs (invalid versions?)");
1963 if (lang == NULL) lang =
"en_GB";
1974 const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1;
1976 chosen_language = lng;
1980 if (strcmp (lng->isocode,
"en_GB") == 0) en_GB_fallback = lng;
1981 if (strncmp(lng->isocode, lang, 5) == 0) chosen_language = lng;
1982 if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng;
1987 if (chosen_language == NULL) {
1988 chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback;
2012 const Sprite *question_mark[FS_END];
2015 question_mark[size] =
GetGlyph(size,
'?');
2021 if (str != NULL) *str = text;
2022 for (
WChar c = Utf8Consume(&text); c !=
'\0'; c = Utf8Consume(&text)) {
2052 const char *NextString()
2059 while (this->i < TAB_COUNT && this->
j >=
_langtab_num[this->i]) {
2074 #ifdef WITH_FREETYPE
2098 if (searcher == NULL) searcher = &pack_searcher;
2100 #ifdef WITH_FREETYPE
2105 memcpy(&backup, &_freetype,
sizeof(backup));
2109 memcpy(&_freetype, &backup,
sizeof(backup));
2111 if (bad_font && base_font) {
2126 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.");
2139 #if !defined(WITH_ICU_LAYOUT)
2154 static char *err_str =
stredup(
"XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled.");