mirror of
https://oauth2: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@github.com/m1ngsama/TNT.git
synced 2026-06-26 05:34:39 +08:00
i18n: tolerate whitespace in language parsing
This commit is contained in:
parent
1897a980d5
commit
86e1ec8e32
3 changed files with 38 additions and 1 deletions
|
|
@ -64,6 +64,8 @@
|
|||
concurrent-session and connection-rate scenarios.
|
||||
- CI memory-leak smoke checks now use an isolated state directory, wait for
|
||||
real SSH readiness, and clean up the exact server PID instead of `pkill`.
|
||||
- Language parsing now tolerates surrounding whitespace and accepts the
|
||||
`english` alias, improving `TNT_LANG` and `:lang` ergonomics.
|
||||
- Refreshed README and quick-reference module maps to match the current
|
||||
`cli_text`, `help_text`, `support_text`, i18n, exec, and rate-limit modules.
|
||||
- NORMAL mode now opens at the latest visible messages instead of the oldest
|
||||
|
|
|
|||
22
src/i18n.c
22
src/i18n.c
|
|
@ -2,9 +2,28 @@
|
|||
|
||||
#include <ctype.h>
|
||||
|
||||
static const char *skip_space(const char *value) {
|
||||
while (value && *value &&
|
||||
isspace((unsigned char)*value)) {
|
||||
value++;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool is_lang_boundary(const char *value) {
|
||||
if (*value == '\0' || *value == '_' || *value == '-' || *value == '.') {
|
||||
return true;
|
||||
}
|
||||
if (!isspace((unsigned char)*value)) {
|
||||
return false;
|
||||
}
|
||||
return *skip_space(value) == '\0';
|
||||
}
|
||||
|
||||
static bool starts_with_lang(const char *value, const char *prefix) {
|
||||
if (!value || !prefix) return false;
|
||||
|
||||
value = skip_space(value);
|
||||
while (*prefix) {
|
||||
if (tolower((unsigned char)*value) !=
|
||||
tolower((unsigned char)*prefix)) {
|
||||
|
|
@ -14,7 +33,7 @@ static bool starts_with_lang(const char *value, const char *prefix) {
|
|||
prefix++;
|
||||
}
|
||||
|
||||
return *value == '\0' || *value == '_' || *value == '-' || *value == '.';
|
||||
return is_lang_boundary(value);
|
||||
}
|
||||
|
||||
bool i18n_try_parse_lang(const char *value, help_lang_t *lang) {
|
||||
|
|
@ -30,6 +49,7 @@ bool i18n_try_parse_lang(const char *value, help_lang_t *lang) {
|
|||
}
|
||||
|
||||
if (starts_with_lang(value, "en") ||
|
||||
starts_with_lang(value, "english") ||
|
||||
starts_with_lang(value, "c") ||
|
||||
starts_with_lang(value, "posix")) {
|
||||
if (lang) *lang = LANG_EN;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,20 @@ TEST(parse_unknown_uses_fallback) {
|
|||
assert(i18n_parse_lang("fr_FR.UTF-8", LANG_ZH) == LANG_ZH);
|
||||
}
|
||||
|
||||
TEST(parse_ignores_surrounding_whitespace) {
|
||||
help_lang_t lang;
|
||||
|
||||
assert(i18n_try_parse_lang(" zh ", &lang) == true);
|
||||
assert(lang == LANG_ZH);
|
||||
assert(i18n_parse_lang("\ten_US.UTF-8\n", LANG_ZH) == LANG_EN);
|
||||
assert(i18n_parse_lang(" english ", LANG_ZH) == LANG_EN);
|
||||
assert(i18n_try_parse_lang("zh CN", &lang) == false);
|
||||
|
||||
setenv("TNT_LANG", " zh ", 1);
|
||||
setenv("LC_ALL", "en_US.UTF-8", 1);
|
||||
assert(i18n_default_lang() == LANG_ZH);
|
||||
}
|
||||
|
||||
TEST(default_prefers_tnt_lang) {
|
||||
setenv("TNT_LANG", "zh_CN.UTF-8", 1);
|
||||
setenv("LC_ALL", "en_US.UTF-8", 1);
|
||||
|
|
@ -123,6 +137,7 @@ int main(void) {
|
|||
|
||||
RUN_TEST(parse_explicit_languages);
|
||||
RUN_TEST(parse_unknown_uses_fallback);
|
||||
RUN_TEST(parse_ignores_surrounding_whitespace);
|
||||
RUN_TEST(default_prefers_tnt_lang);
|
||||
RUN_TEST(default_uses_locale_when_no_tnt_lang);
|
||||
RUN_TEST(text_lookup_matches_language);
|
||||
|
|
|
|||
Loading…
Reference in a new issue