mirror of
https://oauth2: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@github.com/m1ngsama/TNT.git
synced 2026-06-26 05:44:38 +08:00
Add language-keyed i18n string initializers
This commit is contained in:
parent
57d0f931b5
commit
d893351c5a
4 changed files with 25 additions and 2 deletions
|
|
@ -113,6 +113,9 @@
|
||||||
the packaged systemd unit, and release preflight checks that metadata.
|
the packaged systemd unit, and release preflight checks that metadata.
|
||||||
- The Homebrew formula draft now defines a `brew services` entry that runs the
|
- The Homebrew formula draft now defines a `brew services` entry that runs the
|
||||||
installed `tnt` binary with state under `var/tnt`.
|
installed `tnt` binary with state under `var/tnt`.
|
||||||
|
- The i18n helper now supports language-keyed string initializers through
|
||||||
|
`I18N_STRING_MAP`, so future languages can be added incrementally without
|
||||||
|
changing every existing two-language string initializer.
|
||||||
- Split UI-language parsing from localized text lookup: `src/i18n.c` now owns
|
- Split UI-language parsing from localized text lookup: `src/i18n.c` now owns
|
||||||
locale/code parsing, while `src/i18n_text.c` owns the table-driven text
|
locale/code parsing, while `src/i18n_text.c` owns the table-driven text
|
||||||
catalog with coverage checks for every message ID.
|
catalog with coverage checks for every message ID.
|
||||||
|
|
|
||||||
|
|
@ -480,6 +480,10 @@ keys.
|
||||||
fragments.
|
fragments.
|
||||||
- Keep placeholders visible and stable, for example `%s`, `%d`,
|
- Keep placeholders visible and stable, for example `%s`, `%d`,
|
||||||
`<user>`, and `<message>`.
|
`<user>`, and `<message>`.
|
||||||
|
- Use `I18N_STRING(en, zh)` for ordinary two-language entries. Use
|
||||||
|
`I18N_STRING_MAP(I18N_EN(...), I18N_ZH(...))` when an entry needs
|
||||||
|
language-keyed initialization so future languages can be added without
|
||||||
|
changing every existing initializer.
|
||||||
- Every new user-facing string needs tests for at least English fallback
|
- Every new user-facing string needs tests for at least English fallback
|
||||||
and Chinese output while this project has two UI languages.
|
and Chinese output while this project has two UI languages.
|
||||||
|
|
||||||
|
|
@ -488,7 +492,8 @@ keys.
|
||||||
The current `src/i18n_text.c` implementation is a small-project translation
|
The current `src/i18n_text.c` implementation is a small-project translation
|
||||||
table implemented in C, not a full gettext catalog. It is acceptable for two
|
table implemented in C, not a full gettext catalog. It is acceptable for two
|
||||||
languages because message lookup is already split from language parsing in
|
languages because message lookup is already split from language parsing in
|
||||||
`src/i18n.c`, but adding more languages should move toward catalog-like
|
`src/i18n.c`, and localized strings can now be initialized by language key.
|
||||||
|
Adding many more languages should still move toward external catalog-like
|
||||||
storage instead of adding ad hoc branches for every locale.
|
storage instead of adding ad hoc branches for every locale.
|
||||||
|
|
||||||
Relevant conventions:
|
Relevant conventions:
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,12 @@ typedef struct {
|
||||||
const char *text[UI_LANG_COUNT];
|
const char *text[UI_LANG_COUNT];
|
||||||
} i18n_string_t;
|
} i18n_string_t;
|
||||||
|
|
||||||
|
#define I18N_LANG_TEXT(lang, value) [lang] = (value)
|
||||||
|
#define I18N_EN(value) I18N_LANG_TEXT(UI_LANG_EN, value)
|
||||||
|
#define I18N_ZH(value) I18N_LANG_TEXT(UI_LANG_ZH, value)
|
||||||
|
#define I18N_STRING_MAP(...) {{ __VA_ARGS__ }}
|
||||||
#define I18N_STRING(en_text, zh_text) \
|
#define I18N_STRING(en_text, zh_text) \
|
||||||
{{ [UI_LANG_EN] = (en_text), [UI_LANG_ZH] = (zh_text) }}
|
I18N_STRING_MAP(I18N_EN(en_text), I18N_ZH(zh_text))
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
I18N_USERNAME_PROMPT,
|
I18N_USERNAME_PROMPT,
|
||||||
|
|
|
||||||
|
|
@ -80,10 +80,21 @@ TEST(default_uses_locale_when_no_tnt_lang) {
|
||||||
|
|
||||||
TEST(text_lookup_matches_language) {
|
TEST(text_lookup_matches_language) {
|
||||||
i18n_string_t sample = I18N_STRING("fallback", "替代");
|
i18n_string_t sample = I18N_STRING("fallback", "替代");
|
||||||
|
i18n_string_t mapped = I18N_STRING_MAP(
|
||||||
|
I18N_EN("mapped fallback"),
|
||||||
|
I18N_ZH("映射替代")
|
||||||
|
);
|
||||||
|
i18n_string_t english_only = I18N_STRING_MAP(
|
||||||
|
I18N_EN("english only")
|
||||||
|
);
|
||||||
|
|
||||||
assert(strcmp(i18n_string(sample, UI_LANG_EN), "fallback") == 0);
|
assert(strcmp(i18n_string(sample, UI_LANG_EN), "fallback") == 0);
|
||||||
assert(strcmp(i18n_string(sample, UI_LANG_ZH), "替代") == 0);
|
assert(strcmp(i18n_string(sample, UI_LANG_ZH), "替代") == 0);
|
||||||
assert(strcmp(i18n_string(sample, (ui_lang_t)99), "fallback") == 0);
|
assert(strcmp(i18n_string(sample, (ui_lang_t)99), "fallback") == 0);
|
||||||
|
assert(strcmp(i18n_string(mapped, UI_LANG_EN), "mapped fallback") == 0);
|
||||||
|
assert(strcmp(i18n_string(mapped, UI_LANG_ZH), "映射替代") == 0);
|
||||||
|
assert(strcmp(i18n_string(english_only, UI_LANG_ZH),
|
||||||
|
"english only") == 0);
|
||||||
|
|
||||||
assert(strstr(i18n_text(UI_LANG_EN, I18N_USERNAME_PROMPT),
|
assert(strstr(i18n_text(UI_LANG_EN, I18N_USERNAME_PROMPT),
|
||||||
"display name") != NULL);
|
"display name") != NULL);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue