연결된 다중 언어 (i18n) 게이츠비 프로그램

요즘은 게이츠비에서 일한다.js 프로젝트에서 저는 다중 언어(국제화/i18n) 지원을 실현해야 합니다.많은 지침이 있고 다양한 방법/도구를 사용하지만 본고에서 제가 최종적으로 사용한 해결 방안과 제가 직면한 문제점을 보여드리고 싶습니다.
그렇다면 우리는 무엇을 실시해야 하고, 무엇을 실현하고 싶습니까?
  • 집중 설정과 번역.
  • 특정 언어의 정적 페이지를 생성합니다.
  • URL 현지화.
  • 사용자 로케일을 식별하고 구성 요소를 업데이트합니다.
  • 언어 전환 단추를 실현하여 언어 사이를 전환합니다.
  • 외부 의존항을 사용하지 않거나 가능한 한 적게 사용합니다.
  • Take a look at the Github repo with example project and the DEMO


    🌟 각 로켈에 대한 페이지 생성


    코드를 작성하기 전에 URL을 현지화하는 것을 고려해야 합니다.이 예에서는 기본 언어가 URL에 접두어가 없는 것으로 가정합니다.우리는 영어를 기본 언어로 하고 일본어를 제2 언어로 추가할 것이다.
    ╔════════════════════════════════════════════════════╗
    ║       Languages     ║  index.js  ║   page-2.js     ║
    ╠════════════════════════════════════════════════════╣
    ║ English (default)   ║    /       ║   /page-2       ║
    ║ Japanese            ║    /ja     ║   /ja/page-2    ║
    ╚════════════════════════════════════════════════════╝
    
    locales.js 파일에 모든 언어 환경 정의를 포함하는 모듈을 만듭니다.한 언어만 default: true 키가 있어야 한다는 것을 주의하십시오.
    // i18n/locales.js
    
    module.exports = {
      en: {
        path: 'en',
        locale: 'English',
        default: true,
      },
      ja: {
        path: 'ja',
        locale: '日本語',
      },
    };
    
    각 언어에 대해 수동으로 다른 구성 요소를 작성할 필요가 없으며 gatsby-node.js 파일에 다음과 같은 내용을 추가할 수 있습니다. onCreatePage 갈고리는 각 언어 환경에 페이지를 만들고 localeisDefault 도구를 페이지 상하문에 전달합니다.
    // gatsby-node.js
    
    const locales = require('./i18n/locales');
    
    exports.onCreatePage = ({ page, actions }) => {
      const { createPage, deletePage } = actions;
    
      // For each page, we’re deleting it, than creating it again for each
      // language passing the locale to the page context
      return new Promise(resolve => {
        deletePage(page);
    
        Object.keys(locales).map(lang => {
          const isDefault = locales[lang].default || false;
    
          const localizedPath = isDefault
            ? page.path
            : locales[lang].path + page.path;
    
          return createPage({
            ...page,
            path: localizedPath,
            context: {
              locale: lang,
              isDefault,
            },
          });
        });
    
        resolve();
      });
    };
    
    http://localhost:8000/___graphql로 이동하여 모든 페이지를 질의하면 각 로켈에 대해 자동으로 생성된 페이지가 표시됩니다.

    이제 pageContext 를 레이아웃 어셈블리에 전달하여 나중에 localeisDefault를 사용할 수 있습니다.
    {
      allSitePage {
        edges {
          node {
            path
            context {
              isDefault
              locale
            }
          }
        }
      }
    }
    

    🌟 JSON 형식의 번역 추가


    정의된 언어 약정에 따라 JSON 형식으로 i18n/translations/ 폴더에 데이터를 넣습니다. 언어 코드 [name].[language].json 를 포함하는 파일 이름에 접미사를 추가합니다. 예를 들어 data.en.json 또는 data.js.json.
    우선, 프로젝트에 다음과 같은 종속성이 포함되어 있는지 확인해야 합니다.
  • gatsby-transformer-json - JSON 파일에서 컨텐트를 가져옵니다.
  • gatsby-source-filesystem - 폴더의 파일을 조회/i18n/합니다.
  • yarn add gatsby-source-filesystem gatsby-transformer-json
    
    그런 다음 구성gatsby-config.js을 업데이트합니다.
    // gatsby-config.js
    
    module.exports = {
      // ...
      plugins: [
        'gatsby-transformer-json',
        {
          resolve: `gatsby-source-filesystem`,
          options: {
            name: `i18n`,
            path: `${__dirname}/i18n`,
          },
        },
      // ...
      ],
    };
    
    두 언어에 대한 번역을 작성합니다.
    // i18n/translations/en.json
    {
      "title": "Gatsby Default Starter",
      "greeting": "Hi people",
      // ...
    }
    
    // i18n/translations/ja.json
    {
      "title": "Gatsbyデフォルトスターター",
      "greeting": "皆さん、こんにちは",
      // ...
    }
    

    🌟 Locale 갈고리를 사용하여 현재 언어 유지


    게이츠비는 백엔드 @reach/router 에서 사용하기 때문에 URL에서 언어 이름을 추출하고 프로그램을 초기화할 때 사용할 수 있도록 현재pathname에 접근할 수 있습니다. 따라서 초기 데이터를localStorage나 다른 곳에 저장할 필요가 없습니다.

    We can take advantage of react's Context API to share current language value between components.


    // src/hooks/useLocale.js
    
    import React, { createContext, useState, useContext } from 'react';
    import { useLocation } from '@reach/router';
    
    import allLocales from '../../i18n/locales';
    
    const LocaleContext = createContext('');
    
    const LocaleProvider = ({ children }) => {
      const { pathname } = useLocation();
    
      // Find a default language
      const defaultLang = Object.keys(allLocales)
        .filter(lang => allLocales[lang].default)[0];
    
      // Get language prefix from the URL
      const urlLang = pathname.split('/')[1];
    
      // Search if locale matches defined, if not set 'en' as default
      const currentLang = Object.keys(allLocales)
        .map(lang => allLocales[lang].path)
        .includes(urlLang)
        ? urlLang
        : defaultLang;
    
      const [locale, setLocale] = useState(currentLang);
    
      const changeLocale = lang => {
        if (lang) {
          setLocale(lang);
        }
      };
    
      return (
        <LocaleContext.Provider value={{ locale, changeLocale }}>
          {children}
        </LocaleContext.Provider>
      );
    };
    
    const useLocale = () => {
      const context = useContext(LocaleContext);
    
      if (!context) {throw new Error('useLocale must be used within an LocaleProvider');}
    
      return context;
    };
    
    export { LocaleProvider, useLocale };
    
    우리의 갈고리가 되돌아오기 때문에 레이아웃 구성 요소를 포장할 수 있습니다.
    // src/components/app.js
    
    import { LocaleProvider } from '../hooks/useLocale';
    import Layout from './layout';
    
    const App = ({ children, pageContext: { locale, isDefault } }) => (
      <LocaleProvider>
        <Layout locale={locale} isDefault={isDefault}>
          {children}
        </Layout>
      </LocaleProvider>
    );
    // ...
    
    그리고 우리는 LocaleProvider 함수를 사용하여 단추를 사용하여 언어를 바꾸는 방법을 제공할 수 있다.다음 코드를 추가하면 값이 변경될 때마다 새 값이 저장됩니다.
    // src/components/layout.js
    
    import { useLocale } from '../hooks/useLocale';
    
    const Layout = ({ children, pageContext: { locale, isDefault } }) => {
      const { changeLocale } = useLocale();
    
      // Every time url changes we update our context store
      useEffect(() => {
        changeLocale(locale);
      }, [locale]);
      // ...
    };
    

    🌟 Translation hook을 사용하여 데이터 조회

    changeLocale-정적 조회do not take variables를 사용하는 방법은 단점이 있기 때문에 모든 조회 노드를 수동으로 작성해야 합니다.
    검색 응답을 간소화한 다음 현재 언어에 따라 필터를 하는 조수 함수를 만들 것입니다.
    // src/hooks/useTranslation.js
    
    import { useStaticQuery, graphql } from 'gatsby';
    import { useLocale } from './useLocale';
    
    const query = graphql`
      query useTranslations {
        allFile(filter: {relativeDirectory: {eq: "translations"}}) {
          edges {
            node {
              name
              childrenTranslationsJson {
                greeting
                mainPageContent
                secondPageLink
                title
                goHomeLink
                secodPageContent
                secondGreeting
                indexPageTitle
                secondPageTitle
                NotFoundPageTitle
                NotFoundPageContent
              }
            }
          }
        }
      }
    `;
    
    // This hook simplifies query response for current language.
    const useTranslation = () => {
      const { locale } = useLocale();
      const { allFile } = useStaticQuery(query);
    
      // Extract all lists from GraphQL query response
      const queryList = allFile.edges.map(item => {
        const currentFileTitle = Object.keys(item.node).filter(
          item => item !== 'name',
        )[0];
    
        return {
          name: item.node.name,
          ...item.node[currentFileTitle][0],
        };
      });
    
      // Return translation for the current locale
      return queryList.filter(lang => lang.name === locale)[0];
    };
    
    export default useTranslation;
    
    이제 구성 요소locale의 데이터를 번역할 수 있습니다.
    // src/pages/page-2.js
    
    // ...
    import SEO from '../components/seo';
    import useTranslation from '../hooks/useTranslation';
    
    const SecondPage = ({ pageContext }) => {
      const {
        secodPageContent,
        goHomeLink,
        secondGreeting,
        secondPageTitle,
      } = useTranslation();
    
      return (
        <>
          <SEO title={secondPageTitle} />
          <h1>{secondGreeting}</h1>
          <p>{secodPageContent}</p>
    
          {/* ... */}
        </>
      );
    };
    // ...
    

    🌟 폐막사


    마지막으로, 우리는 사용자가 사이트를 정확하게 훑어보고 두 언어 사이를 전환할 수 있도록 허용해야 한다.이것은 로컬 링크와 단추를 통해 전환해야 합니다.여기Github repo에서 확인할 수 있습니다.
    출시된 프로젝트 사용Gatsby's default starter

    우리가 최종적으로 사용하는 i18n은 외부 의존항(또는 가능한 한 적게)을 사용하지 않는다. 상하문 API, 갈고리, 그리고 useStaticQuery의 게이츠비i18n/translations/를 사용하여 각 언어 환경에 페이지를 생성하고createPage() 플러그인으로 번역 데이터를 관리한다.

    Take a look at the Github repo with example project and the DEMO


    링크

  • Gatsby's default starter
  • @reach/router and Gatsby
  • Multilingual Gatsby.js
  • Static vs Normal Queries
  • 🎉 감사합니다:)

    좋은 웹페이지 즐겨찾기