Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support i18n #1339

Merged
merged 46 commits into from
Jan 17, 2023
Merged

feat: support i18n #1339

merged 46 commits into from
Jan 17, 2023

Conversation

brc-dd
Copy link
Member

@brc-dd brc-dd commented Sep 14, 2022

Breaking Changes

  • Legacy i18n stuff is removed/replaced.

    • localePath is removed from useData(). One can have similar functionality using localeIndex or lang property.
  • For people using the default theme, themeConfig.localeLinks is removed in favor of locales.

    Change:

    themeConfig: {
      localeLinks: {
          text: 'English',
          items: [
            { text: '简体中文', link: 'https://cn.vitejs.dev' },
            { text: '日本語', link: 'https://ja.vitejs.dev' },
            { text: 'Español', link: 'https://es.vitejs.dev' }
          ]
      }
    }

    to:

    locales: {
      root: { label: 'English' },
      zh: { label: '简体中文', link: 'https://cn.vitejs.dev' },
      ja: { label: '日本語', link: 'https://ja.vitejs.dev' },
      es: { label: 'Español', link: 'https://es.vitejs.dev' }
    }
  • There are internal changes in Algolia Search and Carbon Ads components.

Features

To use in-built i18n features, one need to create a file structure as following:

docs/
├─ es/
│  ├─ baz.md
├─ fr/
│  ├─ bar.md
├─ foo.md

Then in docs/.vitepress/config:

defineConfig({
  // shared properties and other top-level stuff...
  
  locales: {
    root: {
      label: 'English',
      lang: 'en'
    },
    fr: {
      label: 'French',
      lang: 'fr', // optional, will be added  as `lang` attribute on `html` tag
      link: '/fr/guide' // default /fr/ -- shows on navbar translations menu, can be external

      // other locale specific properties...
    }
  }
})

The following properties can be overridden for each locale (including root):

interface LocaleSpecificConfig<ThemeConfig = any> {
  lang?: string
  dir?: string
  title?: string
  titleTemplate?: string | boolean
  description?: string
  head?: HeadConfig[] // will be merged with existing head entries, duplicate meta tags are automatically removed
  themeConfig?: ThemeConfig // will be shallow merged, common stuff can be put in top-level themeConfig entry
}
  • All of the labels (placeholder texts) of default theme can now be customized. Refer DefaultTheme.Config type for details.

Linked Issues

Todo

I was going through VuePress' implementation, and I think some other things can be done or need testing:

  • Check if the back to home link of the 404 page is locale specific.
  • Allow setting 404 text and other stuff in that page?
  • Allow customizing text of containers at theme level?
    • Markdown renderer is currently not customizable based on theme. We can use something like file name to resolve locale, but I don't think that much work is worth it. Users can still override the labels. Also, IMO the use of default containers is quite limited in projects. We can track this separately if there is significant demand.
  • Optimize DocSearch update? (They are modifying facetFilters in-place to prevent re-initialization in case only the language has changed. But IG most of the projects will be changing other stuff like placeholder/translations too if they are using locales with Algolia. Not sure if this optimization will have any significant impact.)

Notes

  • locales.root is not required if there is no document at root level.

    This is a perfectly fine structure:

    docs/
    ├─ en/
    │  ├─ foo.md
    ├─ es/
    │  ├─ baz.md
    ├─ fr/
       ├─ bar.md
    

    However, VitePress won't redirect / to /en/ by default. You'll need to configure your server for that. On Netlify, the configuration (docs/public/_redirects) may look similar to this:

    /*  /es/:splat  302  Language=es
    /*  /fr/:splat  302  Language=fr
    /*  /en/:splat  302
    

    Pro tip: If using the above approach, you can use nf_lang cookie to persist user's language choice. A very basic way to do this is register a watcher inside setup function of custom theme:

    // docs/.vitepress/theme/index.ts
    
    export default {
      ...DefaultTheme,
      setup() {
        const { lang } = useData()
        watchEffect(() => {
          if (inBrowser) {
            document.cookie = `nf_lang=${lang.value}; expires=Mon, 1 Jan 2024 00:00:00 UTC; path=/`
          }
        })
      }
    }

    For a complete example visit https://github.com/brc-dd/vite-docs (deployed at https://gleeful-rugelach-418cf0.netlify.app/). It's a test repo with combined Vite's docs.

  • For testing purposes you can use these changes by running pnpm add -D vitepress@npm:@brc-dd/vitepress@next

  • Config file can now be stored at docs/.vitepress/config/index.ts too. It allows you to write separate config files for locales inside the same directory and export them from index. (example)

  • Don't override themeConfig.algolia and themeConfig.carbonAds at locale-level. To use multilingual DocSearch, you can have some configuration like this:

    Click to expand
    defineConfig({
      // ...
      themeConfig: {
      // ...
    
        algolia: {
          appId: '34YFD9IUQ2',
          apiKey: '9a9058b8655746634e01071411c366b8',
          indexName: 'vuepress',
          searchParameters: {
            facetFilters: ['tags:v2']
          },
          locales: {
            zh: {
              placeholder: '搜索文档',
              translations: {
                button: {
                  buttonText: '搜索文档',
                  buttonAriaLabel: '搜索文档'
                },
                modal: {
                  searchBox: {
                    resetButtonTitle: '清除查询条件',
                    resetButtonAriaLabel: '清除查询条件',
                    cancelButtonText: '取消',
                    cancelButtonAriaLabel: '取消'
                  },
                  startScreen: {
                    recentSearchesTitle: '搜索历史',
                    noRecentSearchesText: '没有搜索历史',
                    saveRecentSearchButtonTitle: '保存至搜索历史',
                    removeRecentSearchButtonTitle: '从搜索历史中移除',
                    favoriteSearchesTitle: '收藏',
                    removeFavoriteSearchButtonTitle: '从收藏中移除'
                  },
                  errorScreen: {
                    titleText: '无法获取结果',
                    helpText: '你可能需要检查你的网络连接'
                  },
                  footer: {
                    selectText: '选择',
                    navigateText: '切换',
                    closeText: '关闭',
                    searchByText: '搜索提供者'
                  },
                  noResultsScreen: {
                    noResultsText: '无法找到相关结果',
                    suggestedQueryText: '你可以尝试查询',
                    reportMissingResultsText: '你认为该查询应该有结果?',
                    reportMissingResultsLinkText: '点击反馈'
                  }
                }
              }
            }
          }
        }
      }
    })

    These options can be overridden. Refer Algolia's docs on what they do.

  • For RTL support, specify dir: 'rtl' in config and use some RTLCSS PostCSS plugin (https://github.com/MohammadYounes/rtlcss, https://github.com/vkalinichev/postcss-rtl, https://github.com/elchininet/postcss-rtlcss). You'll need to configure your PostCSS plugin to use :where([dir="ltr"]) and :where([dir="rtl"]) as prefixes to prevent CSS specificity issues.

  • Changing locale to say zh will change the URL from /foo (or /en/foo/) to /zh/foo. You can disable this behavior by setting themeConfig.i18nRouting to false.

fix: don't break when locales are not used
fix: make navbar title link to current locale
feat: allow customizing locale link in navbar
feat: allow overriding theme config
feat: support overriding head based on current locale
feat: support customizing title and description
feat: add lang attribute to html based on route
feat: show current and available langs on navbar
fix: refactor types to support locales
fix: group label customization to theme.translations
types/default-theme.d.ts Outdated Show resolved Hide resolved
types/default-theme.d.ts Outdated Show resolved Hide resolved
@kiaking

This comment was marked as outdated.

@brc-dd

This comment was marked as resolved.

@brc-dd brc-dd marked this pull request as ready for review December 21, 2022 08:58
@VoVAllen
Copy link
Contributor

VoVAllen commented Jan 1, 2023

any plan to merge this?

@brc-dd brc-dd self-assigned this Jan 8, 2023
@PierW
Copy link

PierW commented Jan 11, 2023

@yyx990803 hope to see this as soon as possible

@kiaking
Copy link
Member

kiaking commented Jan 12, 2023

We're working on it. Almost done. We're checking if this wouldn't break any ecosystem like Vue and Vite docs. Stay tuned!

@kiaking kiaking merged commit 8de2f44 into main Jan 17, 2023
@kiaking kiaking deleted the feat/i18n-next branch January 17, 2023 13:20
@PierW
Copy link

PierW commented Jan 18, 2023

Finally! thank you! ❤️

@awxiaoxian2020
Copy link
Collaborator

@brc-dd Could you please add docs for outline.label?

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.