From de34940c4dd709fa7103c6961cbe8b410638ffdd Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Mon, 22 Mar 2021 19:27:44 +0200 Subject: Lang: Improvements; macOS menu items Use char pointer ranges for the array of IDs and strings to avoid allocations. Translate macOS menu items. IssueID #192 --- src/lang.c | 53 +++++++++++++++++++++++++++++++++++++++++++--------- src/lang.h | 7 ++++++- src/macos.m | 4 +++- src/ui/labelwidget.c | 24 +----------------------- src/ui/window.c | 12 ++++++------ 5 files changed, 60 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/lang.c b/src/lang.c index d0120798..81afb0d2 100644 --- a/src/lang.c +++ b/src/lang.c @@ -8,13 +8,13 @@ iDeclareType(Lang) iDeclareType(MsgStr) struct Impl_MsgStr { - const char *id; /* these point to null-terminated strings in embedded data */ - const char *str; + iRangecc id; /* these point to null-terminated strings in embedded data */ + iRangecc str; }; int cmp_MsgStr_(const void *e1, const void *e2) { const iMsgStr *a = e1, *b = e2; - return iCmpStr(a->id, b->id); + return cmpCStrNSc_Rangecc(a->id, b->id.start, size_Range(&b->id), &iCaseSensitive); } /*----------------------------------------------------------------------------------------------*/ @@ -35,10 +35,12 @@ static void load_Lang_(iLang *d, const char *id) { const iBlock *data = &blobEn_Embedded; iMsgStr msg; for (const char *ptr = constBegin_Block(data); ptr != constEnd_Block(data); ptr++) { - msg.id = ptr; + msg.id.start = ptr; while (*++ptr) {} - msg.str = ++ptr; + msg.id.end = ptr; + msg.str.start = ++ptr; while (*++ptr) {} + msg.str.end = ptr; /* Allocate the string. The data has already been sorted. */ pushBack_Array(&d->messages->values, &msg); } @@ -62,18 +64,51 @@ void setCurrent_Lang(const char *language) { load_Lang_(d, language); } -const char *cstr_Lang(const char *msgId) { +iRangecc range_Lang(iRangecc msgId) { const iLang *d = &lang_; size_t pos; - const iMsgStr key = { .id = iConstCast(char *, msgId) }; + const iMsgStr key = { .id = msgId }; if (locate_SortedArray(d->messages, &key, &pos)) { return ((const iMsgStr *) at_SortedArray(d->messages, pos))->str; } - fprintf(stderr, "[Lang] missing: %s\n", msgId); fflush(stderr); + fprintf(stderr, "[Lang] missing: %s\n", cstr_Rangecc(msgId)); fflush(stderr); iAssert(iFalse); return msgId; } +const char *cstr_Lang(const char *msgId) { + return range_Lang(range_CStr(msgId)).start; /* guaranteed to be NULL-terminated */ +} + const iString *string_Lang(const char *msgId) { - return collectNewCStr_String(cstr_Lang(msgId)); + return collectNewRange_String(range_Lang(range_CStr(msgId))); +} + +void translate_Lang(iString *textWithIds) { + for (const char *pos = cstr_String(textWithIds); *pos; ) { + iRangecc id; + id.start = strstr(pos, "${"); + if (!id.start) { + break; + } + id.start += 2; + id.end = strchr(id.start, '}'); + iAssert(id.end != NULL); + const size_t idLen = size_Range(&id); + const iRangecc replacement = range_Lang(id); + const size_t startPos = id.start - cstr_String(textWithIds) - 2; + /* Replace it. */ + remove_Block(&textWithIds->chars, startPos, idLen + 3); + insertData_Block(&textWithIds->chars, startPos, replacement.start, size_Range(&replacement)); + pos = cstr_String(textWithIds) + startPos + size_Range(&replacement); + } +} + +const char *translateCStr_Lang(const char *textWithIds) { + if (strstr(textWithIds, "${") == NULL) { + return textWithIds; /* nothing to replace */ + } + iString *text = collectNewCStr_String(textWithIds); + translate_Lang(text); + return cstr_String(text); } diff --git a/src/lang.h b/src/lang.h index 3e9291f2..ea71e531 100644 --- a/src/lang.h +++ b/src/lang.h @@ -6,5 +6,10 @@ void init_Lang (void); void deinit_Lang (void); void setCurrent_Lang (const char *language); -const iString * string_Lang (const char *msgId); +iRangecc range_Lang (iRangecc msgId); + const char * cstr_Lang (const char *msgId); +const iString * string_Lang (const char *msgId); + +void translate_Lang (iString *textWithIds); +const char * translateCStr_Lang (const char *textWithIds); diff --git a/src/macos.m b/src/macos.m index c6c30fa5..12575dd5 100644 --- a/src/macos.m +++ b/src/macos.m @@ -22,6 +22,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "macos.h" #include "app.h" +#include "lang.h" #include "ui/color.h" #include "ui/command.h" #include "ui/keys.h" @@ -462,6 +463,7 @@ void insertMenuItems_MacOS(const char *menuLabel, int atIndex, const iMenuItem * NSApplication *app = [NSApplication sharedApplication]; MyDelegate *myDel = (MyDelegate *) app.delegate; NSMenu *appMenu = [app mainMenu]; + menuLabel = translateCStr_Lang(menuLabel); NSMenuItem *mainItem = [appMenu insertItemWithTitle:[NSString stringWithUTF8String:menuLabel] action:nil keyEquivalent:@"" @@ -469,7 +471,7 @@ void insertMenuItems_MacOS(const char *menuLabel, int atIndex, const iMenuItem * NSMenu *menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:menuLabel]]; [menu setAutoenablesItems:NO]; for (size_t i = 0; i < count; ++i) { - const char *label = items[i].label; + const char *label = translateCStr_Lang(items[i].label); if (label[0] == '\r') { /* Skip the formatting escape. */ label += 2; diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c index c3bc4392..0becd419 100644 --- a/src/ui/labelwidget.c +++ b/src/ui/labelwidget.c @@ -359,29 +359,7 @@ void updateSize_LabelWidget(iLabelWidget *d) { } static void replaceVariables_LabelWidget_(iLabelWidget *d) { - for (const char *label = cstr_String(&d->label); *label; ) { - iRangecc id; - id.start = strstr(label, "${"); - if (!id.start) { - break; - } - id.start += 2; - id.end = strchr(id.start, '}'); - iAssert(id.end != NULL); - /* TODO: Add a lookup that doesn't allocate anything; Lang can handle it. */ - const size_t len = size_Range(&id); - char *key = malloc(len + 1); - memcpy(key, id.start, len); - key[len] = 0; - const char *text = cstr_Lang(key); - const size_t textLen = strlen(text); - free(key); - /* Replace it. */ - size_t startPos = id.start - cstr_String(&d->label) - 2; - remove_Block(&d->label.chars, startPos, len + 3); - insertData_Block(&d->label.chars, startPos, text, textLen); - label = cstr_String(&d->label) + startPos + textLen; - } + translate_Lang(&d->label); } void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { diff --git a/src/ui/window.c b/src/ui/window.c index 2d1deb72..d27d252b 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -1055,12 +1055,12 @@ static void setupUserInterface_Window(iWindow *d) { setAlignVisually_LabelWidget(navMenu, iTrue); setId_Widget(addChildFlags_Widget(navBar, iClob(navMenu), collapse_WidgetFlag), "navbar.menu"); #else - insertMenuItems_MacOS("File", 1, fileMenuItems_, iElemCount(fileMenuItems_)); - insertMenuItems_MacOS("Edit", 2, editMenuItems_, iElemCount(editMenuItems_)); - insertMenuItems_MacOS("View", 3, viewMenuItems_, iElemCount(viewMenuItems_)); - insertMenuItems_MacOS("Bookmarks", 4, bookmarksMenuItems_, iElemCount(bookmarksMenuItems_)); - insertMenuItems_MacOS("Identity", 5, identityMenuItems_, iElemCount(identityMenuItems_)); - insertMenuItems_MacOS("Help", 7, helpMenuItems_, iElemCount(helpMenuItems_)); + insertMenuItems_MacOS("${menu.title.file}", 1, fileMenuItems_, iElemCount(fileMenuItems_)); + insertMenuItems_MacOS("${menu.title.edit}", 2, editMenuItems_, iElemCount(editMenuItems_)); + insertMenuItems_MacOS("${menu.title.view}", 3, viewMenuItems_, iElemCount(viewMenuItems_)); + insertMenuItems_MacOS("${menu.title.bookmarks}", 4, bookmarksMenuItems_, iElemCount(bookmarksMenuItems_)); + insertMenuItems_MacOS("${menu.title.identity}", 5, identityMenuItems_, iElemCount(identityMenuItems_)); + insertMenuItems_MacOS("${menu.title.help}", 7, helpMenuItems_, iElemCount(helpMenuItems_)); #endif } /* Tab bar. */ { -- cgit v1.2.3