Gatsby: Gatsby로 웹사이트 국제화를 위한 공식 가이드 추가

에 만든 2018년 02월 04일  ·  74코멘트  ·  출처: gatsbyjs/gatsby

다른 문제에 대한 내 의견에 대한 반응을 보고 이 문제를 열기로 결정했습니다.

i18n은 생각보다 훨씬 어렵다고 생각합니다. Gatsby가 만든 웹사이트에서 콘텐츠를 국제화하기 위한 공식 문서나 플러그인을 찾을 수 없었습니다. 나는 대부분의 문제를 해결하는 것으로 보이는 jsLingui

documentation

가장 유용한 댓글

얘들아 거의 1년이야 😂

나는 최근에 당신의 gatsby 웹사이트를 즉시 사용할 수 있는 국제화 프레임워크로 만드는 새로운 gatsby 플러그인 gatsby-plugin-intl 을 출시했습니다.

데모: https://gatsby-starter-default-intl.netlify.com

  • react-intl 에서 제공하는 즉시 사용 가능한 국제화 프레임워크

  • 브라우저에서 사용자가 선호하는 언어를 기반으로 자동 리디렉션 지원

  • 단일 페이지 구성 요소에서 다국어 URL 경로를 지원합니다. 즉, pages/en/index.js 또는 pages/ko/index.js 와 같은 별도의 페이지를 만들 필요가 없습니다.

  • 위에서 제안한 것처럼 이제 빌드 시간 동안 현재 언어만 번들로 제공됩니다.

또한 많은 i18n 예제/스타터가 실제로 클라이언트 측에서 렌더링된다는 점을 언급하고 싶습니다. 앱이 SSR로 렌더링되었는지 확인하는 가장 좋은 방법은 소스 코드를 보고 현지화된 텍스트가 있는지 확인하는 것입니다. SEO를 위해 개츠비 웹사이트를 국제화할 때 이 문제를 다시 확인하십시오.

모든 74 댓글

지금까지 나에게 가장 진보된 방법인 GatsbyJS와 함께 i18next를 사용하는 방법에 대한 이 기사 가 있습니다.

그러나 i18next가 "정적 방법"이라고 생각하지 않습니다.

블로그 게시물에 대해 다음과 같은 질문/예약이 있었습니다.
https://twitter.com/semdubois/status/930389055388508160

https://github.com/angeloocana/gatsby-plugin-i18n이 있지만 몇 가지 제한 사항이 있으며 많은 활동/주의를 받지 못하고 있습니다. Gatsby repo 내에서 이동하는 것이 도움이 될 수 있습니다. 저도 적절한 통합 솔루션을 원합니다.

나는 js lingui도 우연히 만났고 특히 v2가 막 나왔을 때 유망해 보입니다.

나도 이것을 알아 내려고 노력하고 있습니다. 포스트에서 i18next 방식을 사용하는 것이 가장 편리하고 직관적으로 느껴지지만 두 가지 질문이 남습니다....

  1. gatsby-plugin-i18n 솔루션과 같은 언어에 대해 다른 마크다운 파일을 어떻게 통합할 수 있습니까?

  2. 이것은 콘텐츠의 정적 렌더링을 완전히 배제합니까?

참고로 @angeloocana

현재 react-intl 사용하여 처리하는 방법에 대한 간략한 요약을 작성하겠습니다. 이 앱은 아직 프로덕션 단계가 아니므로 이 설정에서 여전히 몇 가지 문제를 찾을 수 있지만 지금까지는 잘 작동하는 것 같습니다.

우리는 거의 모든 콘텐츠(Wordpress 블로그에서 마이그레이션)를 Contentfulgatsby-source-contentful 플러그인을 사용하고 있습니다. 그러나 이전에는 이 데이터를 JSON 파일로 가져와 직접 변환하고 gatsby-source-filesystem 플러그인을 사용했습니다( /en/blog/... 와 같은 폴더 구조를 사용했습니다 /de/blog/... ), 따라서 각 노드가 해당 로케일을 알고 있는 한 Contentful을 사용하는지 여부는 실제로 중요하지 않습니다.

또한 버튼 레이블과 같은 일부 텍스트, Contentful에서 제공되지 않는 일부 링크 또는 정적 콘텐츠가 있지만 대신 Transifex 에서 번역되어 리포지토리에 저장된 JSON 파일과 동기화됩니다. 이 부분에서 우리는 i18n 라이브러리를 사용해야 했고 react-intl 를 사용하기로 결정했습니다. 왜냐하면 이미 알고 있고 날짜 및 숫자 형식도 처리한다는 것을 알고 있기 때문입니다. 설정 방법은 다음과 같습니다. https://github.com/gatsbyjs/gatsby/issues/3830#issuecomment -362710469. 그런 다음 템플릿에서 메타 태그 및 <FormattedMessage /> , <FormattedDate /> 등의 구성 요소를 생성할 때 예를 들어 intl.formatMessage 를 사용합니다.

@szimek 내가 당신을 올바르게 이해한다면 게시물이 페이지 디렉토리 아래의 하드 코딩된 경로에 있는 동안 react-intl 구성 요소 텍스트 번역을 처리하게 하시겠습니까?

하드코딩된 경로가 정적으로 렌더링되는 유일한 경로라는 것을 의미합니까? 그리고 i18n 구성 요소 간 번역이 동적으로 렌더링됩니까?

@deltaskelta 귀하의 질문을 이해했는지 잘 모르겠습니다.

현재로서는 사용자 정의 클라이언트 측 라우팅(예: 여기에 설명됨)이 없으며 정적으로 생성된 페이지만 있습니다. post 페이지를 생성할 때(우리는 또한 gatsby-pagination 플러그인의 약간 수정된 버전을 사용하여 로케일별 페이지가 매겨진 indexcategory 페이지를 생성합니다), 다음 코드를 사용하여:

posts.edges.map(({ node }) => {
  const id = node.contentfulid;
  const locale = node.node_locale;

  return createPage({
    path: `/${locale}/blog/posts/${id}`,
    layout: locale,
    component: path.resolve('./src/templates/post-page.jsx'),
    context: {
      id,
      locale,
    },
  });
});

JS를 비활성화한 경우에도 메타 태그를 포함한 모든 콘텐츠가 올바른 언어로 렌더링됩니다.

우리 측에서는 약간의 조정과 함께 i18next 사용하고 있습니다.

주요 원칙은 다음과 같습니다.

  • 로케일은 .json 파일로 사용할 수 있으며 빌드하는 동안 /dist/ 디렉토리로 간단히 이동됩니다.
  • 우리는 onCreatePage ( in gatsby-node.js )를 사용하여 우리가 가지고 있는 언어만큼 많은 정적 버전을 생성할 단일 페이지에서 작업하고 있습니다.
  • 페이지 정보(예: 경로 이름)는 단일 파일에 집중되어 있습니다.

로케일

번역은 페이지당 하나의 네임스페이스(= JSON 파일) + 하나의 글로벌 파일(머리글/바닥글과 같은 공유 텍스트용)로 대부분 페이지별로 그룹화되었습니다.

|- src/
  |- locales/
    |- en/
      |- foo.json
      |- bar.json
    |- fr/
      |- foo.json
      |- bar.json

슬프게도 로케일 수정에 대한 핫 리로딩은 없습니다 👎

i18next

i18next는 다음 구성으로 초기화됩니다.

import i18n from "i18next";
import Backend from "i18next-xhr-backend";
import { reactI18nextModule } from "react-i18next";
import config from "config";  // Our custom configurations env-specifics

const NAMESPACES = [
  "foo",
  "bar",
  ...
];

export default function createI18n() {
  const options = {
    fallbackLng   : false,
    whitelist     : ["en", "fr"],
    ns            : NAMESPACES,
    debug         : config.debug,
    interpolation : {
      escapeValue : false
    },
    react         : {
      wait : true
    },
    backend       : {
      loadPath : `${config.pathPrefix}locales/{{lng}}/{{ns}}.json`
    },
    parseMissingKeyHandler : () => "",  // Display an empty string when missing/loading key
  };

  return i18n
    .use(Backend)
    .use(reactI18nextModule)
    .init(options);
}

페이지 정보

페이지의 모든 i18n 버전을 생성하기 전에 pagesInfos.js 파일에 그룹화한 몇 가지 정보를 알아야 합니다.

module.exports = {
  index : {
    id          : "index",
    namespace   : "home",
    path        : {
      fr : "/",
      en : "/en/"
    }
  },
  projects : {
    id          : "projects",
    namespace   : "projects",
    path        : {
      fr : "/nos-clients/",
      en : "/en/our-clients/"
    }
  },
  // etc...

여기서 키는 페이지 파일 이름 이고 네임스페이스는 로케일 파일 이름 입니다. 다를 수 있습니다 🚨

이 경우:

|- src/
  |- pages/
    |- index.js
    |- projects.js
  |- locales/
    |- en/
      |- home.json
      |- projects.json
    |- fr/
      |- home.json
      |- projects.json

그리고 여기서 path는 우리 페이지의 미래 버전(언어)의 경로 이름입니다.

페이지 작성

위와 같은 예에서 우리의 목표는 홈 및 프로젝트 페이지의 FR + EN 버전을 구축하는 것입니다.

이를 실현하기 위해 전용 함수를 만들었습니다.

/**
 * Generate a custom page informations
 * <strong i="15">@param</strong>  {Object} defaultInfos  Default informations generated by Gatsby
 * <strong i="16">@return</strong> {Object}               Customized page object
 */
function generatePagesInfos(defaultInfos) {
  const pageId = defaultInfos.jsonName.slice(0, -5);  // NOTE: Get pageId from "pageName.json"
  const pageInfos = pagesInfos[pageId];

  const pageFR = {
    ...defaultInfos,
    context : {
      pageId      : pageInfos.id,
      namespace   : pageInfos.namespace,
      language    : "fr"
    },
    path : pageInfos.path.fr
  };

  const pageEN = {
    ...defaultInfos,
    context : {
      pageId      : pageInfos.id,
      namespace   : pageInfos.namespace,
      language    : "en"
    },
    path : pageInfos.path.en
  };

  return [pageFR, pageEN];
}

이 도우미는 onCreatePage 후크 중에 정규식을 통해 각 페이지를 선택하는 동안 사용됩니다.

exports.onCreatePage = async ({ page, boundActionCreators }) => {
  const { createPage, deletePage } = boundActionCreators;

  return new Promise((resolve, reject) => {

    if (page.path.match(page.path.match(/^\/$/))) {
      const i18nPages = generatePagesInfos(page);
      deletePage(page);                         // Remove old default page
      i18nPages.map(page => createPage(page));  // Create custom i18n pages
    }

    if (page.path.match(/^\/projects\/?$/)) {
      const i18nPages = generatePagesInfos(page);
      deletePage(page);
      i18nPages.map(page => createPage(page));
    }

    // etc...

    resolve();
  });
}

이제 사용자 지정 경로 이름(페이지 정보 파일에서)이 있는 각 페이지의 두 가지 버전이 있습니다. pathContext 를 통해 각 페이지에 language 정보를 전달하고 있음을 눈치채셨을 것입니다. 이 값은 각 페이지에서 올바른 언어를 표시하는 데 사용됩니다.

올바른 언어 표시

다음 데코레이터는 현재 페이지의 언어를 자동으로 인식하고 필요한 경우 i18n을 업데이트하여 페이지에 대해 React 클래스를 사용하고 있습니다.

import React from "react";
import PropTypes from "prop-types";
import { i18n } from "context";    // Our custom context

/**
 * <strong i="10">@returns</strong> {React.PureComponent} Component with locales as proptypes
 */
export default function setLanguageFromPage() {

  return WrappedComponent => (
    class extends React.PureComponent {

      static propTypes = {
        pathContext : PropTypes.shape({
          language : PropTypes.string.isRequired
        })
      }

      componentDidMount() {
        const currentLanguage = i18n.language;
        const pageLanguage = this.props.pathContext.language;

        // First request
        if (!currentLanguage) {
          i18n.language = pageLanguage;
        }

        // Only update on language change
        if (currentLanguage !== pageLanguage) {
          i18n.changeLanguage(pageLanguage);
        }
      }

      render() {
        return <WrappedComponent {...this.props} />;
      }

    }
  );

}

그런 다음 페이지에서 호출하십시오.

@setLanguageFromPage()
export default class ProjectsPage extends React.PureComponent {
// ...

이제 i18next의 번역 기능을 사용하기만 하면 됩니다.

결론

👍 빌드 중에 필요한 만큼 많은 버전을 생성하는 단일 소스 파일
👍 손쉬운 페이지 출력 관리
👍 처음에는 노력하지만 나중에는 모든 것이 간단합니다.

👎 로케일에 대한 핫 리로드 없음

나는 그것이 정말로 "정적 삶의 방식"이 아닌 것 같은 느낌이 듭니다. 그러나 그것이 우리가 지금 얻을 수 있는 최선입니다.

이에 대해 어떻게 생각하는지, 어떻게 관리하는지 보고 싶습니다.

추신. 퍽 @szimek , 그것이 내가 며칠 전에 이것을 보여주고 싶었던 것입니다 :)

저는 @angeloocana의 https://github.com/angeloocana/gatsby-plugin-i18n + React-intl을 사용해 왔으며 위의 방법만큼 복잡하지 않지만 몇 가지 제한 사항이 있습니다(repo 문제 참조). React-intl에 대해 그다지 행복하지 않습니다. @triccoder42의 https://github.com/lingui/js-lingui 를 시도해 보고 싶습니다. 시간이 없었습니다.

@monsieurnebo createPage 직전에 deletePage 를 실행하는 목표는 무엇입니까? 귀하의 솔루션이 마음에 들고 구현을 시도했지만 몇 가지 오류가 있습니다.

  • 나도 얻을 잘못된 pathContext.language 사용하지 않고 deletePage

  • 또는 귀하의 예와 같이 deletePage 포함하면 빌드 오류가 발생합니다. (그것은 말한다 TypeError: Cannot read property 'id' of undefined 빌드가에 도달 할 때 run graphql queries 단계)

이것은 내가 지금까지 본 최고의 솔루션입니다.

@deltaskelta 마음에

deletePage 는 Gatsby의 기본 페이지 생성을 취소하는 데 사용됩니다. 이것을 추가하지 않으면 사용자 정의 페이지 기본 페이지가 생성됩니다.

이 행이 있거나 없는 public 디렉토리를 확인하면 차이점을 알 수 있습니다 ;)

귀하의 오류에 대해 코드 없이는 추측하기 어렵습니다. 코드로 저장소를 만들 수 있습니까? 나는 그때 그것을 볼 것입니다.

편집: 예를 들어 관심이 있으십니까?

오, 그것은 deletePage 호출과 관련이 없었습니다. 귀하의 예제를 수정했기 때문에 페이지 개체를 복사하지 않는 문제였습니다. 나는 잠시 동안 js에서 떨어져 있으면 항상 객체 복사에 걸려 넘어집니다.)

@monsieurnebo 나는 당신의 솔루션을 가지고 react-i18next HOC로 래핑된 모든 구성 요소는 구성 요소의 모든 것을 렌더링하기 위해 javascript가 필요한 것 같습니다...

이것이 당신의 끝에서 어떻게 작동하는지 확인할 수 있습니까?

편집: btw 나는 당신의 예에 대한 언급을 놓쳤습니다. 시간이 있다면 전체 예를 보고 싶습니다.

@deltaskelta 여유가 있을 때 예시를 만들어

@monsieurnebo 귀하의 메소드가 문자열을 html로 정적으로 렌더링하지 않고 javascript가 필요한지 확인할 수 있습니까?

네, 그렇기 때문에 완전히 "정적 생활 방식"이 아닙니다 😐

대신 정적 텍스트를 생성하는 플러그인을 원합니다.

흠 알겠습니다. 정적 렌더링은 내가 가야 할 길일 것입니다...

gatsby-node 에 있는 대부분의 페이지에 대한 언어 이름과 함께 컨텍스트가 이미 전달되었기 때문에 각 페이지에 대한 graphql 쿼리에서 메시지 키를 요청하는 것이 너무 어렵지 않을 것이라고 생각했습니다. 그런 식으로 전달하지만 가능하면 i18n 도구를 끝까지 사용하고 싶습니다.

@szimek react-intl 는 js를 사용하지 않고 빌드 단계에서 번역을 어떻게 렌더링합니까?

언급했듯이 Gatsby-plugin-i18n은 정적 텍스트를 생성합니다. 예시를 확인하셨나요?

@deltaskelta 글쎄, 모든 번역은 빌드 시간 동안 사용할 수 있으므로(그래서 여러 레이아웃을 사용하고 있습니다) "그냥 작동" ™️ ;) v2에서 계속 작동하기를 바랍니다... 샘플 앱을 준비할 수 있습니다. 원하다. 파일이 아닌 Contentful로 작업하고 있기 때문에 아직 gatsby-plugin-i18n 에 대해 자세히 살펴보지는 않았습니다.

나는 세부 사항을 읽지 않았지만 여기에 gatsby-plugin-i18n + 내용이 풍부한 콤보에 대한 토론(또는 독백)이 있습니다. https://github.com/angeloocana/gatsby-plugin-i18n/issues/31

@szimek 예에 매우 관심이 있습니다. @sedubois gatsby-plugin-i18n도 정적 텍스트를 생성

이제 왜 렌더링하는 동안 gatsby-node 에서 pathContext 를 통해 react-intl 메시지를 전달하는지 알 것 같습니다.

편집: 이것이 의미가 있는 경우라면 사용된 i18n 라이브러리는 컨텍스트를 통해 메시지를 전달하고 순수한 개츠비 설정인 정적으로 렌더링하고 i18n 라이브러리가 다음과 같은 특별한 경우만 처리하기 때문에 "다소" 관련이 없습니다. js로 날짜와 복수형

모두의 추가 테스트시 i18nextreact-intl HOC 번역 보인다 i18next , 메시지 컨텍스트를 통해 전달 정적으로 렌더링 그래서 경우에도로드하려면 자바 스크립트가 필요합니다 번역 HOC를 사용하면 실행하기 위해 자바스크립트가 필요한 전체 구성 요소가 렌더링됩니다.

반면 react-intlFormattedMessage 구성 요소는 기본 메시지(전달된 컨텍스트를 기반으로 할 수 있음)를 렌더링하고 빌드 시 html에 정적으로 렌더링합니다.

설계상 HTML에서 정적으로 렌더링된 번역을 달성하려는 경우 i18n의 보다 자연스러운 통합이 react-intl과 함께 수행될 것이라고 생각합니다. 너희들이 사용하는 흐름을 내가 잘못 이해했다면 저를 수정하십시오.

@mattferderer 는 여기에서 올바른 아이디어를 가지고 있었지만 약간의 조정이 필요하다고 생각합니다. https://github.com/gatsbyjs/gatsby/issues/3830#issuecomment -362715706

레이아웃은 페이지보다 먼저 렌더링되므로 여러 레이아웃을 만들지 않고는 createPages 함수에서 컨텍스트를 통해 메시지를 전달할 방법이 없습니다(여기서 내가 틀렸다면 수정해 주세요). 그렇다면 i18n을 가장 쉽게 만들기 위해 레이아웃은 children() 호출해야 하고 언어별 다른 레이아웃 효과는 gatsby-node 가 언어별로 다른 경로를 생성하도록 함으로써 달성될 것이라고 생각합니다. 컨텍스트를 통해 메시지를 전달할 수 있는 pages/index 색인 페이지

편집: 혼란스러워서 미안하지만 모든 것이 명확해져서 어딘가에 기록해야 했습니다.

EDIT2: 위에서 확실히 틀렸습니다. 머리글과 바닥글은 레이아웃에 들어가야 합니다. 여러 레이아웃을 만들지 않고 메시지를 받는 방법을 모르겠습니다. 내가 생각할 수있는 유일한 다른 방법은 URL을 분할하고 로케일에 대한 정규식을 사용하는 것입니다 ...하지만 그것은 할 수있는 해킹처럼 느껴집니다.

레이아웃이 하나만 있는 v2가 있는 @KyleAMathews , 경로 또는 언어 키 배열을 기반으로 하는 컨텍스트를 통해 루트 레이아웃 구성 요소에 i18n 메시지와 같은 데이터를 어떻게 전달할 수 있습니까?

이렇게 할 수 있다면 i18n을 구현하기 쉬울 텐데, 여러 레이아웃을 만들지 않고는 어떻게 해야할지 모르겠습니다.

@deltaskelta 여기 우리가 하는 일의 예가 있습니다: https://github.com/szimek/gatsby-react-intl-example. 개별 게시물을 렌더링하는 방법, 각 로케일에 대한 인덱스 페이지를 생성하는 방법, react-intl 구성 요소를 사용하는 방법, react-intl injectIntl HOC를 사용하여 제목을 설정하는 방법(또는 intl.formatMessage 도우미 등을 사용하는 인덱스 페이지의 다른 메타 태그

생성된 페이지는 다음과 같습니다.

  • /en
  • /en/hello-world
  • /pl
  • /pl/witaj-swiecie

실제 앱에서는 gatsby-pagination 의 수정된 버전을 사용하고 있습니다. 원래 버전은 레이아웃 옵션을 지원하지 않기 때문입니다. 또한 동일한 게시물의 번역을 찾을 수 있도록 각 게시물에 대해 post_id 필드를 설정했습니다. 예를 들어 이 데모 앱의 경우 두 게시물의 post_id 합니다.

쩝. 나는 우리가 각 언어에 대해 별도의 사이트맵을 생성해야 할 가능성이 가장 높다는 것을 깨달았습니다. 그러면 Swifttype(우리가 사용하는 검색 엔진)이 어떤 페이지가 있는지 알 수 있습니다.

@deltaskelta 간단히 말해서 각 언어에 대한 페이지 구성 요소가 있고 언어별로 레이아웃 구성 요소가 있습니다. 이것을 할 수 있는 한 가지 방법이 있습니다.

// French
import React from 'react'
import FrenchLayout from '../components/layouts/french'
import ImportantPage from '../components/pages/important-page'

export default ({ data }) => (
  <FrenchLayout>
    <ImportantPage {...data} />
  </FrenchLayout>
)

// French query here
// English
import React from 'react'
import EnglishLayout from '../components/layouts/english'
import ImportantPage from '../components/pages/important-page'

export default ({ data }) => (
  <EnglishLayout>
    <ImportantPage {...data} />
  </EnglishLayout>
)

// English query here

@KyleAMathews 이 파일들은 템플릿이죠? 3개의 페이지 유형과 7개의 언어가 있는 경우 21개의 템플릿이 필요하다는 의미입니까? :)

위의 방법이 가장 최적화된 방법입니다. 각 레이아웃 구성 요소가 다르지 않은 경우 하나의 레이아웃 구성 요소로 결합한 다음 활성 언어에 따라 레이아웃을 전환할 수 있습니다.

나는 세부 사항을 읽지 않았지만 여기에 gatsby-plugin-i18n + contentful 콤보에 대한 토론(또는 독백)이 있습니다. angeloocana/gatsby-plugin-i18n#31

@sedubois , 하하, 네. 요약: 작동하고 이 PR을 통해 Gatsby 문서에 gatsby-starter-contentful-i18n 시작 리포지토리를 포함했습니다. https://github.com/gatsbyjs/gatsby/pull/4138

위의 다른 솔루션, 특히 커뮤니티 플러그인 re: SEO 등과 비교하는 방법에 관심이 있습니다.

@mccrodp 귀하의 솔루션은 내 솔루션과 매우 유사해 보이지만 gatsby-plugin-i18nlayout 옵션을 createPage 에 명시적으로 전달할 필요가 없지만 이를 수행합니다. 무대 뒤에서. 그러나 여전히 여러 레이아웃을 사용하고 있습니다. ;)

@KyleAMathews 제안과 함께 i18n 라이브러리를 사용하는 components/Layout 을 만들고 내 gatsby 레이아웃 폴더를 완전히 삭제했습니다. 이런 식으로 gatsby-node 에서 내 로케일에 대한 페이지를 만들 수 있으며 경로를 포함하여 페이지가 액세스할 수 있는 모든 것에 액세스할 수 있습니다.

그런 다음 로케일을 i18n에 전달하는 레이아웃 구성 요소에 직접 전달할 수 있습니다.

각 페이지 수준 구성 요소를 레이아웃으로 래핑해야 하는 것은 약간 불편하지만, 많은 혼란을 해결하고 내 코드를 많이 단순화했습니다.

안녕하세요 @deltaskelta , 솔루션의 예가 있습니까? 커뮤니티 i18n 플러그인에 업스트림을 푸시하기 위해 배울 수 있는 것이 있는지 알고 싶습니다. 감사 해요.

내 전체 프로젝트가 지금 지저분한 상태에 있지만 기본을 배치 할 수 있다고 생각합니다 ...

  1. 레이아웃 없음 - (제 기억이 맞다면) 레이아웃이 경로나 매우 중요한 다른 것보다 먼저 실행되기 때문에 적절한 메시지 개체를 제공할 수 없었습니다...

  2. 컨텍스트를 통해 gatsby-node 적절한 messageslocale 를 피드...

exports.onCreatePage = ({ page, boundActionCreators }) => {
  const { createPage, deletePage } = boundActionCreators;

  if (page.path.includes('404')) {
    return; // no need for localized 404 pages
  }

  return new Promise(resolve => {
    // if it is not the app page then I need localized static pages
    const pages = localizedPages(page);
    deletePage(page);
    pages.map(page => createPage(page));

    resolve();
  });
};

// to be passed to the localized pages so it can calculate the matchPath
const getMatchPath = lang => {
  return `${locales[lang]['path']}/app/:path`;
};

// this is a helper function that makes pages in each language.
const localizedPages = (page, matchPathFunc) => {
  var pages = [];
  Object.keys(locales).map(lang => {
    const path = locales[lang]['path'] + page.path;

    pages.push({
      ...page,
      path: path,
      matchPath: matchPathFunc ? matchPathFunc(lang) : undefined,
      context: {
        locale: lang,
        messages: locales[lang],
        pathRegex: `/.pages${page.path}./` // so pages can match markdown in their dir
      }
    });
  });

  return pages;
};
  1. 이제 모든 페이지 수준 구성 요소에서 호출해야 하는 전역 레이아웃 구성 요소를 만듭니다...
// this is the main entrypoint for the layout to the site
const GlobalLayout = ({ locale, children, path }) => {
  const theme = getTheme();
  return (
    <MuiThemeProvider theme={theme}>
      <CssBaseline>
        <IntlProvider locale={locale} messages={locales[locale]}>
          <div>
            <Header locale={locale} messages={locales[locale]} path={path} />
            {children}
          </div>
        </IntlProvider>
      </CssBaseline>
    </MuiThemeProvider>
  );
};
  1. 컨텍스트에서 전달된 적절한 로케일 및 메시지가 있는 페이지 수준 구성 요소로 전역 레이아웃 구성 요소를 호출합니다.
const BlogPost = ({ data, pathContext, location }) => {
  const { locale } = pathContext;
  return (
    <GlobalLayout locale={locale} path={location.pathname}>
      <FullWidth>
        <h1>{data.markdownRemark.frontmatter.title}</h1>
        <h3>{data.markdownRemark.frontmatter.date}</h3>
        <div dangerouslySetInnerHTML={{ __html: data.markdownRemark.html }} />
      </FullWidth>
    </GlobalLayout>
  );
};

이 코드를 정리하고 재구성해야 합니다. 작동할 수 있다는 것을 증명하기 위해 빠르게 작업을 수행했고 나중에 다시 방문할 것이기 때문입니다. 이 코드가 요점을 제공하기를 바랍니다.

js-lingui를 사용하여 메시지를 번역하는 gatsby 스타터를 만들었습니다.
https://github.com/dcroitoru/gatsby-starter-i18n-lingui

실제 앱에서는 원래 버전이 레이아웃 옵션을 지원하지 않기 때문에 수정된 버전의 gatsby-pagination을 사용하고 있습니다. 또한 동일한 게시물의 번역을 찾을 수 있도록 각 게시물에 대해 post_id 필드를 설정했습니다. 예를 들어 이 데모 앱의 경우 두 게시물 모두 동일한 post_id를 갖습니다.

@szimek 수정한 개츠비 페이지네이션을 공유할 수 있는 기회가 있습니까? 나 자신도 비슷한 문제를 겪고 있기 때문에 매우 보고 싶습니다.

@martynhoyer패치 가 병합 되었으므로 gatsby-pagination 의 원래 버전으로 다시 전환했습니다. 어떤 문제가 있습니까?

안녕하세요 @sgoudie
저는 이 튜토리얼을 사용하고 있습니다: https://www.gatsbyjs.org/blog/2017-10-17-building-i18n-with-gatsby/ 하지만 locales/{lang}/*.json 찾을 수 없습니다. 아무도 단서가 있습니까?
2018-04-25 12_04_13-o intermedium agora e banco inter

내 구성:
gasbty-node.js
```javascriptexports.onPostBuild = () => {
console.log('로케일 ​​복사')
fs.copySync(
path.join(__dirname, '/src/locales'),
path.join(__dirname, '/공개/로케일')
)
}

```

추가하다

exports.onPostBootstrap = () => {
    console.log("Copying locales");
    fs.copySync(
        path.join(__dirname, "/src/locales"),
        path.join(__dirname, "/public/locales")
    );
};

gatsby-node.js

@ThiagoMiranda 나는 같은 문제에 직면하고 있었고 gatsby develop 가 onPostBuild를 호출하지 않고 gatsby build 만 호출한다는 것을 깨달았습니다. onPostBootstrap은 매번 호출됩니다.

레이아웃에서 https://moz.com/learn/seo/hreflang-tag 를 만드는 방법을 아는 사람이 있습니까?

@RobinHerzog 헬멧을 사용하여 템플릿으로 만들고 있습니다. 그것들은 페이지 유형에 따라 다르므로 적어도 우리의 경우에는 레이아웃에서 생성하는 것이 합리적이지 않습니다.

@szimek 답변 감사합니다. 이해하지만 제 경우에는 레이아웃에 포함하는 것이 흥미로울 것입니다.

<link rel="alternate" href={Route['en-us'][this.props.data.prismicDocument.data.group]} hreflang="en-us" /> <link rel="alternate" href={Route['fr-fr'][this.props.data.prismicDocument.data.group]} hreflang="fr-fr" />

지금은 말씀하신 대로 모든 템플릿에서 해당 줄을 복사하세요.

나는 React/JavaScript로 개발을 시작하고 있지만 i18n을 지원하기 위해 본 모든 것이 너무 복잡했습니다. 다음은 가장 일반적인 사용법에 대한 내 작업입니다. wise-starter

라이브 다시 로드, SEO 친화적 및 기본 언어는 URL의 키를 사용하지 않습니다.
모든 .js 페이지는 모든 언어에 대해 생성됩니다.
오류를 방지하려면 모든 언어에 대해 모든 레이아웃 및 .md를 생성해야 합니다.
LangSelect 및 Link 구성 요소는 i18n smart입니다.

저를 도와주시고 어떻게 제 코드와 스타일을 개선할 수 있는지 설명해 주시면 감사하겠습니다.

@Tom-Pichaud, 페이지 구성 요소에 메시지를 전달하지 않기 때문에 정적으로 렌더링되지 않을 것이라고 생각합니다.

gatsby-node 의 마크다운 i18n 설정은 사람들이 여기서 하는 것과 비슷해 보이지만 페이지 구성 요소에서 자바스크립트를 비활성화한 상태에서 정적 렌더링을 얻는지 궁금합니다.

예, 정적 렌더링을 얻습니다. 어쨌든 그것이 목표였습니다. i18n-react 는 트릭을 수행합니다!

@TomPichaud 언급한 i18n-react가 js-lingui 보다 나은 방법을 공유할 수 있습니까?

내가 이해하지 못하는 한 가지는 번역된 메시지(복수화 및 친척 제외)를 로드하기 위해 외부 패키지가 실제로 필요하다는 것입니다.

정적 콘텐츠가 있는 간단한 사이트의 경우 각 언어 onCreatePage 대한 페이지를 복제하고 로케일을 context .

// some file with the locales
const locales = {
  en: {
    path: 'en',
    default: true,
  },
  pt: {
    path: 'pt',
  },
}
// gatsby-node.js
exports.onCreatePage = ({ page, boundActionCreators }) => {
  const { createPage, deletePage } = boundActionCreators

  return new Promise(resolve => {
    deletePage(page)

    Object.keys(locales).map(lang => {
      const localizedPath = locales[lang].default
        ? page.path
        : locales[lang].path + page.path

      return createPage({
        ...page,
        path: localizedPath,
        context: {
          locale: lang,
        },
      })
    })

    resolve()
  })
}

그런 다음 실제 페이지에서 컨텍스트의 로케일을 사용하여 graphql의 필터를 사용하여 콘텐츠를 쿼리합니다.

/data/home/en.js/data/home/pt.js 홈 콘텐츠가 있다고 가정해 보겠습니다.

import React from 'react'

const IndexPage = ({ pathContext: { locale }, ...props }) => {
  const { childHomeJson: data } = props.data.allFile.edges[0].node

  return <div>{data.hello}</div>
}

export const query = graphql`
  query HomeContent($locale: String) {
    allFile(filter: { name: { eq: $locale } }) {
      edges {
        node {
          childHomeJson {
            hello
          }
        }
      }
    }
  }
`

export default IndexPage

netlifyCMS(i18n을 지원할 때까지 약간 장황하지만) 및 JSON 파일의 이미지(Gatsby의 파일 시스템이 가져오도록 상대 경로로 새 NodeField를 만들어야 함)와 잘 작동합니다.

대부분의 경우 이것으로 충분하지 않습니까?

나는 여전히 테스트 중이며 프로덕션에서 이것을 사용하지 않았지만 현지화된 링크와 같은 보류 중인 문제를 해결하기 위해 로케일에 대해 react의 컨텍스트 API를 사용할 생각입니다.

@pbrandone 이것은 나에게 훌륭한 접근 방식인 것 같습니다. 비슷한 것이 공식적으로 문서화되어야 한다고 생각합니다.

모든 의견에 감사드립니다. 여기에서 논의된 아이디어의 양은 잘 문서화된 i18n 지원에 대한 요구를 분명히 나타냅니다.

@pbrandone 이 쿼리에서 IndexPage 자식 구성 요소가 사용하는 모든 키를 명시적으로 지정하고 props를 통해 모든 구성 요소에 번역을 전달해야 한다는 뜻인가요?

또한 복수화 규칙과 상대 날짜를 사용하므로 어쨌든 추가 로케일별 데이터를 로드해야 합니다.

그러나 간단한 경우에 라이브러리 없이 i18n을 수행하는 방법과 가장 인기 있는 라이브러리에서 수행하는 방법에 대한 공식 문서가 있다는 데 동의합니다.

@szimek 음 , 이 경우에는 그렇습니다.

react-intl(또는 다른 i18n 라이브러리)을 추가하는 것은 매우 쉽습니다.

// in src/components/layout/index.js

import React from 'react'
import { IntlProvider, addLocaleData } from 'react-intl'

// Locale data
import enData from 'react-intl/locale-data/en'
import ptData from 'react-intl/locale-data/pt'

// Messages
import en from '../../data/en.json'
import pt from '../../data/pt.json'

const messages = { en, pt }

addLocaleData([...enData, ...ptData])

const Layout = ({ locale, children }) => (
  <IntlProvider locale={locale} messages={messages[locale]}>
    {children}
  </IntlProvider>
)

export default Layout

그런 다음 페이지에서:

import React from 'react'
import { FormattedMessage } from 'react-intl'

import Layout from '../components/layouts'

const IndexPage = ({ pathContext: { locale } }) => (
  <Layout locale={locale}>
    <FormattedMessage id="hello" />
  </Layout>
)

export default IndexPage

그러나 그러면 여러 JSON 파일(예: 페이지당)을 사용할 수 없으며 해당 파일의 모든 CMS 데이터를 사용하여 graphql의 힘으로 쿼리하고 변환할 수 없습니다.
예를 들어, graphql 접근 방식을 사용하면 해당 JSON 파일의 이미지 경로가 있는 일부 키가 로케일별로 다른 이미지를 로드하고 여전히 gatsby-image 를 사용할 수 있습니다.
그런 다음 netlify CMS를 추가하여 JSON 파일을 편집하세요 😃

gatsby v2를 제대로 살펴보지는 않았지만 분명히 자식 구성 요소에서 쿼리할 수 있는 StaticQuery 구성 요소가 있습니다(제가 틀렸다면 누군가 저를 수정해 주세요!)

이 경우 React Context를 생성하여 로케일을 어디에서나 사용할 수 있도록 한 다음 로케일 필터링을 사용하여 각 구성 요소에서 필요한 키를 쿼리할 수 있습니다.

@pbrandone 당신이 맞습니다. 정적으로 그런 식으로 렌더링합니다. 과거에 테스트했지만 실패한 것을 기억합니다. 하지만 그건 제가 gatsby가 어떻게 작동하는지 제대로 이해하기 전이었습니다. gatsby 브라우저에서 react-intl 설정을 했을 수도 있습니다. 이 설정은 javascript 없이는 렌더링되지 않을 수 있습니다. 내 솔루션은 이제 귀하의 솔루션과 같습니다.

@KyleAMathews 페이지를 Gatsby v2로 업데이트하려고 하는데 react-intl 설정 및 graphql 쿼리에 문제가 있습니다.

이전에 언어별 레이아웃을 사용하여 Gatsby v1( https://github.com/szimek/gatsby-react-intl-example) 에서 언어 데이터를 로드하는 방법을 설명했습니다 src/templates/Post.js 구성 요소가 있고 src/templates/Post.en.js , src/templates/Post.de.js 와 같은 언어 관련 구성 요소는 언어 데이터만 로드하고 언어에 구애받지 않는 구성 요소를 렌더링합니다.

이전 댓글(https://github.com/gatsbyjs/gatsby/issues/3853#issuecomment-367115380)에서 각 페이지 구성 요소에 언어별 쿼리가 있는 예를 보여주었습니다.

문제는 createPage 호출할 때 이러한 언어별 구성 요소(예: src/templates/Post.en.js )의 이름을 component 옵션으로 전달하지만 graphql 쿼리는 이 __exactly 모든 languages__에 대해 동일한 때문에 언어에 독립적 구성 요소는, (이것은에 따라 locale ,하지만 난 그것을 통과하고있어 context ). 이러한 모든 언어별 구성 요소에서 정확히 동일한 쿼리를 반복하는 것을 피하고 싶습니다.

그것을 해결하는 방법에 대한 아이디어가 있습니까? 이 쿼리를 변수로 추출할 수 있습니까? 시도했을 때 Gatsby는 쿼리 및 프래그먼트 이름이 동일하다고 불평합니다...

최근에 다국어 URL 경로 및 브라우저 언어 감지 기능이 있는 기본 Gatsby 스타터를 추가했습니다. (데모)

gatsby-starter-default-intl

특징:

  • react-intl 에서 제공하는 현지화(다국어).

  • browser-lang 에서 제공하는

  • 단일 페이지 구성 요소 내에서 다국어 URL 경로를 지원합니다. 즉, pages/en/index.js 또는 pages/ko/index.js 와 같은 별도의 페이지를 만들 필요가 없습니다.

  • 최소한의 수정 으로 gatsby-starter-default 를 기반으로 합니다.

@wiziple 감사합니다! 정말 흥미롭게 보입니다. https://github.com/wiziple/gatsby-starter-default-intl/blob/master/src/i18n/withIntl.js#L38 ;) 다행히도 여전히 작동합니다. 웹팩 4에서...

https://github.com/wiziple/gatsby-starter-default-intl/blob/master/src/i18n/withIntl.js#L6 에서 같은 방식으로 로케일 데이터를 로드할 수 있습니까? 우리는 6개(곧 7개 언어)를 지원하므로 페이지를 구축하는 데 사용할 언어만 로드할 수 있다면 좋을 것입니다. 가능하지 않더라도 큰 문제는 아닙니다. 다행히도 이러한 로케일 데이터 파일은 상대적으로 작습니다.

제 경우에는 모든 페이지가 모든 언어로 번역되지 않기 때문에(단일 "소스" 언어가 없음) 이러한 페이지를 생성하는 방법도 살펴봐야 합니다. 따라서 onCreatePage 가 있는 솔루션은 작동하지 않을 것입니다. 나의 경우에는.

바라건대 이것은 모든 언어별 페이지 구성 요소에서 동일한 graphql 쿼리로 내 문제를 해결할 것입니다.

@szimek
내가 관리하는 웹사이트에는 14개 언어가 있으며 각 언어 파일은 12-15KB입니다. SEO 데이터를 생성하려면 빌드 시 각 언어 라우터에 적합한 언어를 제공해야 한다고 확신합니다. 그래서 나는 모든 언어를 제공하지 않고 이것을 어떻게 처리할 수 있는지 잘 모르겠습니다.

때때로 모든 언어로 번역된 모든 페이지를 제공하기가 어렵다는 것을 이해합니다. gatsby-node.js onCreatePage 에 일부 예외를 제공하여 이 문제를 해결할 수 있습니다. 제 경우에는 언어 라우터에 상관없이 번역된 언어를 제공하지 않는 것으로 간단히 해결했습니다. 😆 스타터 README.md에서 제작에 관한 쇼케이스 홈페이지를 찾아 성능을 확인하실 수 있습니다.

@wiziple 정말 감사합니다!

나는 번역을 위해 동적 require 트릭과 함께 withIntl 구성 요소를 사용했으며(사용에 대한 단점이 있는지 전혀 모릅니다) 잘 작동하는 것 같습니다. 모든 언어에 대한 단일 페이지 구성 요소를 사용하여 여러 언어별 페이지 구성 요소에서 동일한 graphql 쿼리를 처리하는 방법과 같은 문제를 해결했습니다.

@wiziple repo 공유에 감사드립니다. 😄 🎉

lingui가 더 나은 대안인 것 같습니다. @dcroitoru 가 좋은 예에 대해 적절한 인정을 받지 못했다고 생각합니다. Gatsby 2.0으로 푸시하려면 약간의 사랑이 필요합니다.

최신 버전의 Gatsby뿐 아니라 Lingui와 함께 완전한 스타터가 여전히 필요하지만 Lingui가 실제로 정말 훌륭하다는 데 동의합니다. 언급된 스타터는 비공식적이며 내가 마지막으로 확인할 때 일부 기능이 누락되었습니다(예: lingui 컴파일을 즉석에서 실행하기 위해 로더 사용). Lingui 의 작성자 Lingui v3가 출시되면 문서를 제공할 것이라고 말했습니다 (곧 나타날 것으로 보입니다).

NB: CMS(DatoCMS)를 통합한 후 i18n 라이브러리에 대한 필요성이 감소했지만 CMS에서 위치를 찾지 못하는 일부 문자열과 복수화 및 아마도 나중에 다른 것들을 위해 여전히 Lingui가 필요합니다. 내 코드베이스에 보관하고 싶습니다.

어쨌든 제 경우에는 gatsby-plugin-i18n의 존재가 유지 관리되지 않고 혼란스러운 이름을 가지고 있기 때문에 상황을 상당히 혼란스럽게 만들었으며 js-lingui 및 CMS와 같은 다른 정말 좋은 솔루션에서 주의를 끌었습니다. 함께 파악하고 조립하는 동안.

여러분을 돕기 위해 이 스타터를 만들었습니다: https://github.com/smakosh/gatsby-starter-i18n
기사: https://dev.to/smakosh/implement-i18n-to-a-gatsby-site-5ala

react-intl 통합으로 두 가지 국제화 예제를 만들었습니다.

첫 번째 예 는 js 청크(내가 확인한 다른 플러그인에서는 찾을 수 없는 것)의 현재 번역만 번들링하는 데 중점을 둡니다.

두 번째 예제에서는 동적 쿼리를 사용하여 지정된 페이지/언어 조합에 대해 요청된 번역만 제공하는 데 중점을 둡니다.

이 예제가 누군가에게 유용하기를 바랍니다.

또한 https://github.com/gatsbyjs/gatsby/issues/3853#issuecomment -395432693(좀 더 깊이 있음)에 있는 내용과 함께 빠른 중간 게시물을 작성했습니다(여기에 게시하는 것을 잊었습니다).

관심 있는 사람을 위한 https://blog.significa.pt/i18n-with-gatsby-528607b4da81

오래된 호는 30일 동안 활동이 없으면 닫힙니다. 이 문제는 20일 동안 잠잠했으며 오래된 것으로 표시됩니다. 이 문제를 계속 공개하려면 여기에서 답장하거나 "not stale" 레이블을 추가하세요!

얘들아 거의 1년이야 😂

나는 최근에 당신의 gatsby 웹사이트를 즉시 사용할 수 있는 국제화 프레임워크로 만드는 새로운 gatsby 플러그인 gatsby-plugin-intl 을 출시했습니다.

데모: https://gatsby-starter-default-intl.netlify.com

  • react-intl 에서 제공하는 즉시 사용 가능한 국제화 프레임워크

  • 브라우저에서 사용자가 선호하는 언어를 기반으로 자동 리디렉션 지원

  • 단일 페이지 구성 요소에서 다국어 URL 경로를 지원합니다. 즉, pages/en/index.js 또는 pages/ko/index.js 와 같은 별도의 페이지를 만들 필요가 없습니다.

  • 위에서 제안한 것처럼 이제 빌드 시간 동안 현재 언어만 번들로 제공됩니다.

또한 많은 i18n 예제/스타터가 실제로 클라이언트 측에서 렌더링된다는 점을 언급하고 싶습니다. 앱이 SSR로 렌더링되었는지 확인하는 가장 좋은 방법은 소스 코드를 보고 현지화된 텍스트가 있는지 확인하는 것입니다. SEO를 위해 개츠비 웹사이트를 국제화할 때 이 문제를 다시 확인하십시오.

얘들아 거의 1년이야 😂

나는 최근에 당신의 gatsby 웹사이트를 즉시 사용할 수 있는 국제화 프레임워크로 만드는 새로운 gatsby 플러그인 gatsby-plugin-intl 을 출시했습니다.

데모: https://gatsby-starter-default-intl.netlify.com

  • react-intl 에서 제공하는 즉시 사용 가능한 국제화 프레임워크
  • 브라우저에서 사용자가 선호하는 언어를 기반으로 자동 리디렉션 지원
  • 단일 페이지 구성 요소에서 다국어 URL 경로를 지원합니다. 즉, pages/en/index.js 또는 pages/ko/index.js 와 같은 별도의 페이지를 만들 필요가 없습니다.
  • 위에서 제안한 것처럼 이제 빌드 시간 동안 현재 언어만 번들로 제공됩니다.

또한 많은 i18n 예제/스타터가 실제로 클라이언트 측에서 렌더링된다는 점을 언급하고 싶습니다. 앱이 SSR로 렌더링되었는지 확인하는 가장 좋은 방법은 소스 코드를 보고 현지화된 텍스트가 있는지 확인하는 것입니다. SEO를 위해 개츠비 웹사이트를 국제화할 때 이 문제를 다시 확인하십시오.

@wiziple 감사합니다. Gatsby를 현지화하기 위한 솔루션을 찾는 데 미쳐가고 있었습니다.
내가 요점을 이해하지 못했을 수도 있지만 하나의 파일에 모든 언어 문자열이 있습니까?
동일한 구성 요소 구조를 사용하여 각 언어의 JSON을 더 많은 파일로 분할할 수 있습니까?

@cant89 요점은 gatsby develop 또는 gatsby build 합니다.
모든 JSON 파일을 가져와 중첩된 개체로 병합하면 평면 개체로 변환할 수도 있습니다.
https://github.com/yahoo/react-intl/wiki/Upgrade-Guide#flatten -messages-object

i18n에 대한 좋은 예제 설정이 있습니다. https://github.com/gatsbyjs/gatsby/tree/master/examples/using-i18n. 우리는 i18n 프레임워크에 대한 의견이 없습니다. 취향에 맞게 하나만 선택하세요.

i18n에 대한 좋은 예제 설정이 있습니다. https://github.com/gatsbyjs/gatsby/tree/master/examples/using-i18n. 우리는 i18n 프레임워크에 대한 의견이 없습니다. 취향에 맞게 하나만 선택하세요.

멋진, 감사합니다. 시도해 보겠습니다!
어쨌든 readme의 링크가 깨졌습니다. 아마도 https://using-i18n.netlify.com/ 을 의미합니까?

@wardpeet 예제에서 정적 번역 문자열을 생성합니까(빌드 시)? 아니면 런타임 중에 텍스트를 생성합니까?

@monsieurnebo 는 빌드 시간처럼 보입니다.

@cant89 우리는 여전히 dns를 업데이트하고 있으므로 곧 사용 가능합니다. using-i18n.netlify.com/ 이 올바른 링크입니다.

@monsieurnebo 빌드시입니다. 모든 것이 정적으로 구축될 수 있도록 각 언어에 대한 웹사이트 사본을 생성합니다. 이것은 모든 것이 .html일 뿐이므로 웹사이트가 빠르게 유지된다는 것을 의미합니다.

이것을 묻는 다른 곳이 확실하지 않지만 약간 관련이 있습니다. 이 플러그인이 gatsby의 pathPrefix 합니까?

i.e. 
// gatsby-config.js

modules.exports = {
    pathPrefix: 'bar'
}

https://foo.com => https://foo.com/bar

but now my language locales will now be https://foo.com/bar/de-DE/
when I think I would prefer it be https://foo.com/de-DE/bar if that makes sense.

흠 흥미롭네요. pathPrefix가 도메인을 domain.com/prefix 로 만드는 것과 같이 일반적으로 전자가 더 합리적이라고 생각합니다. 따라서 Gatsby를 하위 디렉토리에 설치하지 않으면 루트를 변경합니다. 하위 디렉토리는 필요하지 않습니다. 하위 디렉토리를 사용하는 경우 접두어를 언어가 깨뜨리는 이후로 변경하면 됩니다.

이제 질문이 나타납니다. 처음에 pathPrefix 를 사용하는 이유는 무엇입니까?

참조: pathPrefix 문서

안녕,

여기서 논의의 대부분은 개츠비 사이트를 i18n하는 방법에 관한 것입니다. 그러나 POC가 작동하는 것과 최적화된 생산 준비 시스템을 갖는 것에는 차이가 있습니다.

코드 분할 및 i18n 파일에 대한 자세한 내용과 이 스레드의 대부분의 솔루션이 최적화되지 않은 이유에 관심이 있다면 이 문제가 유용하다는 것을 알게 될 것입니다.

이 페이지가 도움이 되었나요?
0 / 5 - 0 등급

관련 문제

timbrandin picture timbrandin  ·  3코멘트

ferMartz picture ferMartz  ·  3코멘트

totsteps picture totsteps  ·  3코멘트

3CordGuy picture 3CordGuy  ·  3코멘트

magicly picture magicly  ·  3코멘트