Thứ hai, 09/12/2019 | 00:00 GMT+7

Menu điều hướng được quốc tế hóa trong Gatsby.js


Trong một bài trước, Tạo trang web đa ngôn ngữ với Gatsby , tôi đã xây dựng kodou.me . Kodou có version tiếng Nhật và tiếng Anh. Bài viết hơi dài nên tôi không nói về một số tiện ích tôi đã sử dụng và cách xây dựng menu chuyển của trang web.

Tóm tắt nhanh

Trong bài trước của ta , ta đã xây dựng một trang bằng tiếng Nhật và tiếng Anh. Ngôn ngữ mặc định của trang là tiếng Anh. Điều này nghĩa là ta có hai loại URL:

  • Các trang tiếng Nhật: kodou.me/ja/team
  • Các trang tiếng Anh kodou.me/team

Các version trang khác nhau được viết bằng Cosmic JS . Ta làm cho Gatsby biết về các ngôn ngữ mà ta sử dụng trong /config/languages . Trong gatsby-node.js , ta tạo các trang của bạn bằng cách sử dụng các mẫu mà ta đưa vào dữ liệu từ Cosmic JS.

Đây là version đơn giản của mảng team-members do Cosmic JS trả về có thể trông như thế nào.

teamMembers = [
  {
    title: 'CEO',
    fullName: 'Jack Misteli',
    content: 'The CEO of the Company',
    locale: 'en'
  },
  {
    title: 'CEO',
    fullName: 'ジャック・ミステリ',
    content: '会社のCEO',
    locale: 'ja'
  }
]

Sau khi nhận được teamMembers ta tạo hai đối tượng jaTeamMembersenTeamMembers . Ta điền các templates/team với jaTeamMembers để tạo /ja/teamenTeamMembers để tạo /team .

Nhận thức về ngôn ngữ trang web

Điều quan trọng là trở thành một công dân web tốt và làm cho các trang web ta tạo ra có thể truy cập được. Vì vậy, điều đầu tiên ta cần làm là thêm ngôn ngữ của ta vào metadata trang web của ta . Nó cũng có thể giúp bạn nhận được nhiều kết quả tìm kiếm được nhắm đến hơn.

Mô-đun: gatsby-config.js
module.export = {
  siteMetadata: {
    title: `Kodou`,
    description: `Kodou site description`,
    author: `Jack Misteli `,
    languages
  },
  //....

Trong ứng dụng Gatsby của ta , ta cũng truyền cho mẫu của bạn ngôn ngữ hiện tại trong ngữ cảnh của trang.

Mô-đun: pageGenerator.js
// langs contains the languages of our blog and default langKey is the default language of the site
// To be fully programmatic we could calculate langs
// here langs = ['en', 'ja'] and defaultLangKey = 'en'
const { langs, defaultLangKey } = require('../config/languages')
const path = require(`path`)
const { localizeUrl, createLanguagesObject } = require('../utils/localization')

module.exports = async (options, createPage, graphql) => {
  const {query, pageName} = options
  let templateName = options.templateName ? options.templateName : pageName
  const result = await graphql(query)
  if (result.errors)
      console.error(result.errors)

  const cosmicJSData = createLanguagesObject(langs)

  Object.values(result.data)[0].edges.forEach(({ node }) => {
  cosmicJSData[node.locale].push(node)
  })

  // we create a new page for each language
  langs.forEach(lang => {
    createPage({
      // the localizeUrl function creates a url which takes into consideration what the default language is
      path: localizeUrl(lang, defaultLangKey, '/team'),
      component: path.resolve(`src/templates/team.js`),
      context: {
      profiles: profiles[lang],
      // Here we pass the current language to the page
      lang
    }
  })
  })
}

Bây giờ ta có thể truy cập lang trong các mẫu của ta

const { lang } = props.pageContext;

Sử dụng API quốc tế hóa

Intl API được sử dụng để so sánh chuỗi, định dạng số và định dạng ngày giờ. Nó có rất nhiều tính năng thú vị mà ta sẽ không khám phá ở đây. Ta sẽ chỉ sử dụng nó ở đây để hiển thị ngày ở định dạng thích hợp.

Ta đang thêm gói react-intl trong file Layout của ta .

Mô-đun: layout.js
import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import "../styles/main.scss"
import Header from "./header"
import { IntlProvider, FormattedDate } from "react-intl"

const Layout = ({ children, location, lang }) => {

  // We populated the siteMetaData in `gatsby-config.js` and are extracting it here for some extra language context
  // The best practice here would be to  directly get that data from `config` but I want to show different ways to do it
  const data = useStaticQuery(graphql`
    query SiteInfoQuery {
      site {
        siteMetadata {
          title
          languages {
            defaultLang
            langs
          }
        }
      }
}
  `)
  // langs is an array of all the supported languages
  // defaultLang is the default site language
  // title is the website's title
  const {langs, defaultLang, title} = data.site.siteMetadata

  return (
    // We use IntlProvider to set the default language of our page
    <IntlProvider
      locale={lang}
      defaultLocale={defaultLang}
    >
      <Header 
        location={location}
        defaultLang={defaultLang}
        languages={langs}
        siteTitle={title} />
        <main className="section">
          <div className="container"> 
            {children}
          </div>
        </main>
        <footer>
          <div className="footer">
            <div className="content has-text-centered">
            {/* FormattedDate will format our date according to the language we set in IntlProvider locale prop */}
              © <FormattedDate value={new Date()}
               year="numeric"
                month="long"
                day="numeric"
                weekday="long" />, Built by 
              <a href="https://jmisteli.com"> Jack Misteli</a>
            </div>
          </div>
        </footer>
    </IntlProvider>
  )
}

export default Layout

Khi trang được tạo bằng tiếng Anh, <FormattedDate> sẽ trả về Monday, December 9, 2019 . Khi trang được tạo bằng tiếng Nhật <FormattedDate> sẽ trả về 2019年12月9日月曜日.

Tạo menu

Bạn có thể thấy rằng trong Layout ta có thành phần Header . Ta chuyển tất cả thông tin ngôn ngữ vào tiêu đề ngoại trừ ngôn ngữ hỗ trợ hiện tại. Ta không vượt qua nó vì tôi muốn chỉ cho bạn một cách khác đối với ngôn ngữ hiện tại của trang.

import { Link } from "gatsby"
import PropTypes from "prop-types"
import React from "react"
import { getCurrentLangKey, getLangs, getUrlForLang } from 'ptz-i18n'
import langmap from 'langmap'
import { localizeUrl, buildMenu } from '../../utils/localization'

const Header = ({ languages, location, defaultLang}) => {

  const url = location.pathname
  const currentLangKey = getCurrentLangKey(languages, defaultLang, url)

  // Create a home link by adding a slash before the language and if it
  const homeLink = localizeUrl(currentLangKey, defaultLang, '/')

  // Get langs return language menu information

  // langsMenu will allow us to build a dropdown with all the available language options
  const langsMenu = buildMenu(languages, defaultLang, currentLangKey, url)
  // On the `/team` page this will return the following array
  //  [{selected: true, link: "/team/", langKey: "en"},
  //  {selected: false, link: "/ja/team/", langKey: "ja"}]

  // All the navigation menu item titles
  const allLanguageTitles = {
    'en':['Concept', 'Work', 'Team', 'News', 'Contact'],
    'ja': ['コンセプト', '仕事', 'チーム', 'ニュース', '連絡先']
  }

  // Selecting the current language and default to english titles
  const currentLanguageTitles = allLanguageTitles[currentLangKey] || allLanguageTitles['en']

  // allNavigationLinks contains all the pages name, with urls in every supported language
  const allNavigationLinks = currentLanguageTitles.map((page, i) => ({
    name: page,
    url: `${homeLink.replace(defaultLang, '')}${allLanguageTitles.en[i].toLowerCase()}`
  }))
  // On the English page it will return 
  // [{name: "Concept", url: "/concept"}, {name: "Work", url: "/work"}, {name: "Team", url: "/team"}...]
  // [{name: "コンセプト", url: "/ja/concept"}, {name: "仕事", url: "/ja/work"}, {name: "チーム", url: "/ja/team"} ...]

  return (
    <nav>
      <Link to={homeLink} className="navbar-item">
        HOME
      </Link>
      {allLinks.map((link, i) => (
      <Link key={i} to={link.url} className="navbar-item">
        {link.name.toUpperCase()}
      </Link>
      ))}

      <div className="navbar-language-menu">
        <div className="current-language">
        // langmap is an object with the language keys as object keys and english, original versions of the language
        {langmap[langKey]['englishName']}
        </div>
        <div className="all-languages-dropdown">
          {langsMenu.map((lang)=>(
            !lang.selected && 
            <Link key={lang.langKey} to={lang.link} className="navbar-item">
            {langmap[lang.langKey]['englishName']}
            </Link>
          ))}
        </div>
      </div>
    </nav>
)}

export default Header

Và thế là xong, bạn có một menu chuyển bằng các ngôn ngữ khác nhau điều chỉnh các liên kết của nó theo ngôn ngữ hiện tại của user . Nếu bạn muốn kiểm tra các chức năng tiện ích mà tôi đã xây dựng, chúng có sẵn trong repo GitHub .


Tags:

Các tin liên quan