diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lang.c | 53 | ||||
-rw-r--r-- | src/lang.h | 7 | ||||
-rw-r--r-- | src/macos.m | 4 | ||||
-rw-r--r-- | src/ui/labelwidget.c | 24 | ||||
-rw-r--r-- | src/ui/window.c | 12 |
5 files changed, 60 insertions, 40 deletions
@@ -8,13 +8,13 @@ iDeclareType(Lang) | |||
8 | iDeclareType(MsgStr) | 8 | iDeclareType(MsgStr) |
9 | 9 | ||
10 | struct Impl_MsgStr { | 10 | struct Impl_MsgStr { |
11 | const char *id; /* these point to null-terminated strings in embedded data */ | 11 | iRangecc id; /* these point to null-terminated strings in embedded data */ |
12 | const char *str; | 12 | iRangecc str; |
13 | }; | 13 | }; |
14 | 14 | ||
15 | int cmp_MsgStr_(const void *e1, const void *e2) { | 15 | int cmp_MsgStr_(const void *e1, const void *e2) { |
16 | const iMsgStr *a = e1, *b = e2; | 16 | const iMsgStr *a = e1, *b = e2; |
17 | return iCmpStr(a->id, b->id); | 17 | return cmpCStrNSc_Rangecc(a->id, b->id.start, size_Range(&b->id), &iCaseSensitive); |
18 | } | 18 | } |
19 | 19 | ||
20 | /*----------------------------------------------------------------------------------------------*/ | 20 | /*----------------------------------------------------------------------------------------------*/ |
@@ -35,10 +35,12 @@ static void load_Lang_(iLang *d, const char *id) { | |||
35 | const iBlock *data = &blobEn_Embedded; | 35 | const iBlock *data = &blobEn_Embedded; |
36 | iMsgStr msg; | 36 | iMsgStr msg; |
37 | for (const char *ptr = constBegin_Block(data); ptr != constEnd_Block(data); ptr++) { | 37 | for (const char *ptr = constBegin_Block(data); ptr != constEnd_Block(data); ptr++) { |
38 | msg.id = ptr; | 38 | msg.id.start = ptr; |
39 | while (*++ptr) {} | 39 | while (*++ptr) {} |
40 | msg.str = ++ptr; | 40 | msg.id.end = ptr; |
41 | msg.str.start = ++ptr; | ||
41 | while (*++ptr) {} | 42 | while (*++ptr) {} |
43 | msg.str.end = ptr; | ||
42 | /* Allocate the string. The data has already been sorted. */ | 44 | /* Allocate the string. The data has already been sorted. */ |
43 | pushBack_Array(&d->messages->values, &msg); | 45 | pushBack_Array(&d->messages->values, &msg); |
44 | } | 46 | } |
@@ -62,18 +64,51 @@ void setCurrent_Lang(const char *language) { | |||
62 | load_Lang_(d, language); | 64 | load_Lang_(d, language); |
63 | } | 65 | } |
64 | 66 | ||
65 | const char *cstr_Lang(const char *msgId) { | 67 | iRangecc range_Lang(iRangecc msgId) { |
66 | const iLang *d = &lang_; | 68 | const iLang *d = &lang_; |
67 | size_t pos; | 69 | size_t pos; |
68 | const iMsgStr key = { .id = iConstCast(char *, msgId) }; | 70 | const iMsgStr key = { .id = msgId }; |
69 | if (locate_SortedArray(d->messages, &key, &pos)) { | 71 | if (locate_SortedArray(d->messages, &key, &pos)) { |
70 | return ((const iMsgStr *) at_SortedArray(d->messages, pos))->str; | 72 | return ((const iMsgStr *) at_SortedArray(d->messages, pos))->str; |
71 | } | 73 | } |
72 | fprintf(stderr, "[Lang] missing: %s\n", msgId); fflush(stderr); | 74 | fprintf(stderr, "[Lang] missing: %s\n", cstr_Rangecc(msgId)); fflush(stderr); |
73 | iAssert(iFalse); | 75 | iAssert(iFalse); |
74 | return msgId; | 76 | return msgId; |
75 | } | 77 | } |
76 | 78 | ||
79 | const char *cstr_Lang(const char *msgId) { | ||
80 | return range_Lang(range_CStr(msgId)).start; /* guaranteed to be NULL-terminated */ | ||
81 | } | ||
82 | |||
77 | const iString *string_Lang(const char *msgId) { | 83 | const iString *string_Lang(const char *msgId) { |
78 | return collectNewCStr_String(cstr_Lang(msgId)); | 84 | return collectNewRange_String(range_Lang(range_CStr(msgId))); |
85 | } | ||
86 | |||
87 | void translate_Lang(iString *textWithIds) { | ||
88 | for (const char *pos = cstr_String(textWithIds); *pos; ) { | ||
89 | iRangecc id; | ||
90 | id.start = strstr(pos, "${"); | ||
91 | if (!id.start) { | ||
92 | break; | ||
93 | } | ||
94 | id.start += 2; | ||
95 | id.end = strchr(id.start, '}'); | ||
96 | iAssert(id.end != NULL); | ||
97 | const size_t idLen = size_Range(&id); | ||
98 | const iRangecc replacement = range_Lang(id); | ||
99 | const size_t startPos = id.start - cstr_String(textWithIds) - 2; | ||
100 | /* Replace it. */ | ||
101 | remove_Block(&textWithIds->chars, startPos, idLen + 3); | ||
102 | insertData_Block(&textWithIds->chars, startPos, replacement.start, size_Range(&replacement)); | ||
103 | pos = cstr_String(textWithIds) + startPos + size_Range(&replacement); | ||
104 | } | ||
105 | } | ||
106 | |||
107 | const char *translateCStr_Lang(const char *textWithIds) { | ||
108 | if (strstr(textWithIds, "${") == NULL) { | ||
109 | return textWithIds; /* nothing to replace */ | ||
110 | } | ||
111 | iString *text = collectNewCStr_String(textWithIds); | ||
112 | translate_Lang(text); | ||
113 | return cstr_String(text); | ||
79 | } | 114 | } |
@@ -6,5 +6,10 @@ void init_Lang (void); | |||
6 | void deinit_Lang (void); | 6 | void deinit_Lang (void); |
7 | 7 | ||
8 | void setCurrent_Lang (const char *language); | 8 | void setCurrent_Lang (const char *language); |
9 | const iString * string_Lang (const char *msgId); | 9 | iRangecc range_Lang (iRangecc msgId); |
10 | |||
10 | const char * cstr_Lang (const char *msgId); | 11 | const char * cstr_Lang (const char *msgId); |
12 | const iString * string_Lang (const char *msgId); | ||
13 | |||
14 | void translate_Lang (iString *textWithIds); | ||
15 | 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. */ | |||
22 | 22 | ||
23 | #include "macos.h" | 23 | #include "macos.h" |
24 | #include "app.h" | 24 | #include "app.h" |
25 | #include "lang.h" | ||
25 | #include "ui/color.h" | 26 | #include "ui/color.h" |
26 | #include "ui/command.h" | 27 | #include "ui/command.h" |
27 | #include "ui/keys.h" | 28 | #include "ui/keys.h" |
@@ -462,6 +463,7 @@ void insertMenuItems_MacOS(const char *menuLabel, int atIndex, const iMenuItem * | |||
462 | NSApplication *app = [NSApplication sharedApplication]; | 463 | NSApplication *app = [NSApplication sharedApplication]; |
463 | MyDelegate *myDel = (MyDelegate *) app.delegate; | 464 | MyDelegate *myDel = (MyDelegate *) app.delegate; |
464 | NSMenu *appMenu = [app mainMenu]; | 465 | NSMenu *appMenu = [app mainMenu]; |
466 | menuLabel = translateCStr_Lang(menuLabel); | ||
465 | NSMenuItem *mainItem = [appMenu insertItemWithTitle:[NSString stringWithUTF8String:menuLabel] | 467 | NSMenuItem *mainItem = [appMenu insertItemWithTitle:[NSString stringWithUTF8String:menuLabel] |
466 | action:nil | 468 | action:nil |
467 | keyEquivalent:@"" | 469 | keyEquivalent:@"" |
@@ -469,7 +471,7 @@ void insertMenuItems_MacOS(const char *menuLabel, int atIndex, const iMenuItem * | |||
469 | NSMenu *menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:menuLabel]]; | 471 | NSMenu *menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:menuLabel]]; |
470 | [menu setAutoenablesItems:NO]; | 472 | [menu setAutoenablesItems:NO]; |
471 | for (size_t i = 0; i < count; ++i) { | 473 | for (size_t i = 0; i < count; ++i) { |
472 | const char *label = items[i].label; | 474 | const char *label = translateCStr_Lang(items[i].label); |
473 | if (label[0] == '\r') { | 475 | if (label[0] == '\r') { |
474 | /* Skip the formatting escape. */ | 476 | /* Skip the formatting escape. */ |
475 | label += 2; | 477 | 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) { | |||
359 | } | 359 | } |
360 | 360 | ||
361 | static void replaceVariables_LabelWidget_(iLabelWidget *d) { | 361 | static void replaceVariables_LabelWidget_(iLabelWidget *d) { |
362 | for (const char *label = cstr_String(&d->label); *label; ) { | 362 | translate_Lang(&d->label); |
363 | iRangecc id; | ||
364 | id.start = strstr(label, "${"); | ||
365 | if (!id.start) { | ||
366 | break; | ||
367 | } | ||
368 | id.start += 2; | ||
369 | id.end = strchr(id.start, '}'); | ||
370 | iAssert(id.end != NULL); | ||
371 | /* TODO: Add a lookup that doesn't allocate anything; Lang can handle it. */ | ||
372 | const size_t len = size_Range(&id); | ||
373 | char *key = malloc(len + 1); | ||
374 | memcpy(key, id.start, len); | ||
375 | key[len] = 0; | ||
376 | const char *text = cstr_Lang(key); | ||
377 | const size_t textLen = strlen(text); | ||
378 | free(key); | ||
379 | /* Replace it. */ | ||
380 | size_t startPos = id.start - cstr_String(&d->label) - 2; | ||
381 | remove_Block(&d->label.chars, startPos, len + 3); | ||
382 | insertData_Block(&d->label.chars, startPos, text, textLen); | ||
383 | label = cstr_String(&d->label) + startPos + textLen; | ||
384 | } | ||
385 | } | 363 | } |
386 | 364 | ||
387 | void init_LabelWidget(iLabelWidget *d, const char *label, const char *cmd) { | 365 | 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) { | |||
1055 | setAlignVisually_LabelWidget(navMenu, iTrue); | 1055 | setAlignVisually_LabelWidget(navMenu, iTrue); |
1056 | setId_Widget(addChildFlags_Widget(navBar, iClob(navMenu), collapse_WidgetFlag), "navbar.menu"); | 1056 | setId_Widget(addChildFlags_Widget(navBar, iClob(navMenu), collapse_WidgetFlag), "navbar.menu"); |
1057 | #else | 1057 | #else |
1058 | insertMenuItems_MacOS("File", 1, fileMenuItems_, iElemCount(fileMenuItems_)); | 1058 | insertMenuItems_MacOS("${menu.title.file}", 1, fileMenuItems_, iElemCount(fileMenuItems_)); |
1059 | insertMenuItems_MacOS("Edit", 2, editMenuItems_, iElemCount(editMenuItems_)); | 1059 | insertMenuItems_MacOS("${menu.title.edit}", 2, editMenuItems_, iElemCount(editMenuItems_)); |
1060 | insertMenuItems_MacOS("View", 3, viewMenuItems_, iElemCount(viewMenuItems_)); | 1060 | insertMenuItems_MacOS("${menu.title.view}", 3, viewMenuItems_, iElemCount(viewMenuItems_)); |
1061 | insertMenuItems_MacOS("Bookmarks", 4, bookmarksMenuItems_, iElemCount(bookmarksMenuItems_)); | 1061 | insertMenuItems_MacOS("${menu.title.bookmarks}", 4, bookmarksMenuItems_, iElemCount(bookmarksMenuItems_)); |
1062 | insertMenuItems_MacOS("Identity", 5, identityMenuItems_, iElemCount(identityMenuItems_)); | 1062 | insertMenuItems_MacOS("${menu.title.identity}", 5, identityMenuItems_, iElemCount(identityMenuItems_)); |
1063 | insertMenuItems_MacOS("Help", 7, helpMenuItems_, iElemCount(helpMenuItems_)); | 1063 | insertMenuItems_MacOS("${menu.title.help}", 7, helpMenuItems_, iElemCount(helpMenuItems_)); |
1064 | #endif | 1064 | #endif |
1065 | } | 1065 | } |
1066 | /* Tab bar. */ { | 1066 | /* Tab bar. */ { |