Eugeny / tabby

A terminal for a more modern age
https://tabby.sh
MIT License
59.55k stars 3.4k forks source link

Translate menu in macOS #10049

Open yuantao313 opened 1 week ago

yuantao313 commented 1 week ago

Describe the problem: In macOS, my language is Chinese, the menu is still shown in English while the main screen is shown in Chinese correctly.

To Reproduce: Switch macOS to Chinese:

截屏2024-11-08 22 39 51
piersandro commented 1 week ago

That menu is in English in all languages. It depends on Electron not on Tabby.

DehanLUO commented 4 days ago

That menu is in English in all languages. It depends on Electron not on Tabby.

Thank you for your response. I’d like to offer a small clarification regarding the menu language in the top-left corner of macOS. It seems that this menu is not directly tied to Electron. From my investigation, I’ve found that it is possible to modify the language displayed in this menu by adjusting the following section of code:

https://github.com/Eugeny/tabby/blob/ac6f60f1ae9ca754b22f15e06cf55a7574b1f9d5/app/lib/app.ts#L247-L330

For example, I made the following changes to the code:

private setupMenu () {
    const template: MenuItemConstructorOptions[] = [
        {
            label: 'Application',
            submenu: [
                { role: 'about', label: '关于' },
                { type: 'separator' },
                {
                    label: '偏好设置',
                    accelerator: 'Cmd+,',
                    click: async () => {
                        if (!this.hasWindows()) {
                            await this.newWindow()
                        }
                        this.windows[0].send('host:preferences-menu')
                    },
                },
                { type: 'separator' },
                { role: 'services', label: '服务', submenu: [] },
                { type: 'separator' },
                { role: 'hide', label: '隐藏' },
                { role: 'hideOthers', label: '隐藏其他窗口' },
                { role: 'unhide', label: '显示全部' },
                { type: 'separator' },
                {
                    label: '退出',
                    accelerator: 'Cmd+Q',
                    click: () => {
                        this.quitRequested = true
                        app.quit()
                    },
                },
            ],
        },
        {
            label: '编辑',
            submenu: [
                { role: 'undo', label: '关于' },
                { role: 'redo', label: '重做' },
                { type: 'separator' },
                { role: 'cut', label: '剪切' },
                { role: 'copy', label: '复制' },
                { role: 'paste', label: '粘贴' },
                { role: 'pasteAndMatchStyle', label: '格式化粘贴' },
                { role: 'delete', label: '删除' },
                { role: 'selectAll', label: '全选' },
            ],
        },
        {
            label: '视图',
            submenu: [
                { role: 'toggleDevTools', label: '开发者工具' },
                { type: 'separator' },
                { role: 'togglefullscreen', label: '全屏' },
            ],
        },
        {
            role: 'window', label: '窗口',
            submenu: [
                { role: 'minimize' },
                { role: 'zoom' },
                { type: 'separator' },
                { role: 'front' },
            ],
        },
        {
            role: 'help', label: '帮助',
            submenu: [
                {
                    label: 'Website',
                    click () {
                        shell.openExternal('https://eugeny.github.io/tabby')
                    },
                },
            ],
        },
    ]

    if (process.env.TABBY_DEV) {
        template[2].submenu['unshift']({ role: 'reload', label: '重载' })
    }

    Menu.setApplicationMenu(Menu.buildFromTemplate(template))
}

And here’s a gif demonstrating the result:

screenshot

It seems that adding some additional logic to match the language settings and update the label accordingly could be an effective way to ensure the menu reflects the chosen language.

DehanLUO commented 4 days ago

@yuantao313 Could you kindly confirm if this aligns with the intended outcome?

screenshot

Modification
private setupMenu () {
    function getEffectiveLocale () {
        const preferredLanguages = app.getPreferredSystemLanguages()

        if (preferredLanguages[0].startsWith('zh')) {
            return 'zh-CN'
        } else if (preferredLanguages[0].startsWith('en')) {
            return 'en'
        } else {
            return 'en'
        }
    }
    const locale = getEffectiveLocale()
    const translations = {
        en: {
            about: 'About Tabby',
            preferences: 'Preferences',
            services: 'Services',
            hide: 'Hide',
            hideOthers: 'Hide Others',
            unhide: 'Show All',
            quit: 'Quit',
            edit: 'Edit',
            undo: 'Undo',
            redo: 'Redo',
            cut: 'Cut',
            copy: 'Copy',
            paste: 'Paste',
            pasteAndMatchStyle: 'Paste and Match Style',
            'delete': 'Delete',
            selectAll: 'Select All',
            view: 'View',
            toggleDevTools: 'Togggle Developer Tools',
            togglefullscreen: 'Toggle Full Screen',
            window: 'Window',
            reload: 'Reload',
            minimize: 'Minimize',
            zoom: 'Zoom',
            front: 'Bring All to Front',
            help: 'Help',
            website: 'Website',
        },
        'zh-CN': {
            about: '关于Tabby',
            preferences: '偏好设置',
            services: '服务',
            hide: '隐藏',
            hideOthers: '隐藏其他窗口',
            unhide: '显示全部',
            quit: '退出',
            edit: '编辑',
            undo: '撤销',
            redo: '重做',
            cut: '剪切',
            copy: '复制',
            paste: '粘贴',
            pasteAndMatchStyle: '格式化粘贴',
            'delete': '删除',
            selectAll: '全选',
            view: '视图',
            toggleDevTools: '开发者工具',
            togglefullscreen: '全屏',
            window: '窗口',
            reload: '重载',
            minimize: '最小化',
            zoom: '缩放',
            front: '前置所有窗口',
            help: '帮助',
            website: '网站',
        },
    }
    const t = translations[locale]
    const template: MenuItemConstructorOptions[] = [
        {
            label: 'Application',
            submenu: [
                { role: 'about', label: t.about },
                { type: 'separator' },
                {
                    label: t.preferences,
                    accelerator: 'Cmd+,',
                    click: async () => {
                        if (!this.hasWindows()) {
                            await this.newWindow()
                        }
                        this.windows[0].send('host:preferences-menu')
                    },
                },
                { type: 'separator' },
                { role: 'services', label: t.services, submenu: [] },
                { type: 'separator' },
                { role: 'hide', label: t.hide },
                { role: 'hideOthers', label: t.hideOthers },
                { role: 'unhide', label: t.unhide },
                { type: 'separator' },
                {
                    label: t.quit,
                    accelerator: 'Cmd+Q',
                    click: () => {
                        this.quitRequested = true
                        app.quit()
                    },
                },
            ],
        },
        {
            label: t.edit,
            submenu: [
                { role: 'undo', label: t.undo },
                { role: 'redo', label: t.redo },
                { type: 'separator' },
                { role: 'cut', label: t.cut },
                { role: 'copy', label: t.copy },
                { role: 'paste', label: t.paste },
                { role: 'pasteAndMatchStyle', label: t.pasteAndMatchStyle },
                { role: 'delete', label: t.delete },
                { role: 'selectAll', label: t.selectAll },
            ],
        },
        {
            label: t.view,
            submenu: [
                { role: 'toggleDevTools', label: t.toggleDevTools },
                { type: 'separator' },
                { role: 'togglefullscreen', label: t.togglefullscreen },
            ],
        },
        {
            role: 'window', label: t.window,
            submenu: [
                { role: 'minimize', label: t.minimize },
                { role: 'zoom', label: t.zoom },
                { type: 'separator' },
                { role: 'front', label: t.front },
            ],
        },
        {
            role: 'help', label: t.help,
            submenu: [
                {
                    label: t.website,
                    click () {
                        shell.openExternal('https://eugeny.github.io/tabby')
                    },
                },
            ],
        },
    ]

    if (process.env.TABBY_DEV) {
        template[2].submenu['unshift']({ role: 'reload', label: t.reload })
    }

    Menu.setApplicationMenu(Menu.buildFromTemplate(template))
}