Gatsby: Tambahkan panduan resmi untuk menginternasionalkan situs web dengan Gatsby

Dibuat pada 4 Feb 2018  ·  74Komentar  ·  Sumber: gatsbyjs/gatsby

Melihat reaksi atas komentar saya tentang masalah lain , saya memutuskan untuk membuka masalah ini.

Saya pikir i18n jauh lebih sulit dari yang seharusnya. Saya tidak dapat menemukan dokumentasi atau plugin resmi untuk menginternasionalkan konten di situs web buatan Gatsby. Saya menemukan jsLingui , yang tampaknya menyelesaikan sebagian besar masalah, tetapi masih belum ada panduan tentang pemeliharaan, misalnya, file/halaman penurunan harga dalam bahasa yang berbeda.

documentation

Komentar yang paling membantu

Hai guys udah hampir setahun

Saya baru-baru ini merilis plugin gatsby baru gatsby -plugin-intl yang dengan mudah menjadikan situs web gatsby Anda sebagai kerangka internasionalisasi di luar kotak.

DEMO: https://gatsby-starter-default-intl.netlify.com

  • Kerangka internasionalisasi luar biasa yang didukung oleh react-intl

  • Mendukung pengalihan otomatis berdasarkan bahasa pilihan pengguna di browser

  • Mendukung rute url multi-bahasa dalam satu komponen halaman. Ini berarti Anda tidak perlu membuat halaman terpisah seperti pages/en/index.js atau pages/ko/index.js .

  • Seperti yang disarankan beberapa dari kalian di atas, sekarang hanya menggabungkan bahasa saat ini selama waktu pembuatan.

Juga, saya ingin menyebutkan bahwa banyak contoh/pemula i18n sebenarnya dirender di sisi klien. Cara terbaik untuk memeriksa apakah aplikasi dirender sebagai SSR adalah dengan melihat kode sumber dan memeriksa apakah ada teks yang dilokalkan. Harap periksa kembali masalah ini ketika Anda menginternasionalkan situs web gatsby Anda untuk SEO.

Semua 74 komentar

Ada artikel tentang menggunakan i18next dengan GatsbyJS , yang merupakan metode paling canggih sejauh ini bagi saya.

Tapi saya tidak merasa i18next adalah "cara statis".

Tentang posting blog, saya punya pertanyaan/reservasi ini:
https://twitter.com/semdubois/status/930389055388508160

Ada https://github.com/angeloocana/gatsby-plugin-i18n tetapi memiliki beberapa keterbatasan dan tidak menerima banyak aktivitas/perhatian. Mungkin membantu untuk memindahkannya ke dalam repo Gatsby. Saya juga akan menyukai solusi konsolidasi yang tepat.

Saya menemukan js lingui juga dan tampaknya menjanjikan, terutama dengan v2 yang baru saja keluar.

Saya juga mencoba mencari tahu ini. Menggunakan metode i18next pada posting adalah yang paling nyaman dan terasa intuitif, tetapi saya memiliki dua pertanyaan....

  1. bagaimana saya bisa memasukkan file penurunan harga yang berbeda untuk bahasa seperti dalam solusi gatsby-plugin-i18n?

  2. Apakah ini sepenuhnya mengabaikan rendering statis konten?

FYI @angeloocana

Saya akan menulis ringkasan singkat tentang bagaimana kami menanganinya saat ini menggunakan react-intl . Aplikasi ini belum dalam produksi, jadi kami mungkin masih menemukan beberapa masalah dengan penyiapan ini, namun sejauh ini tampaknya berfungsi dengan baik.

Kami menyimpan hampir semua konten kami (yang dimigrasikan dari blog Wordpress kami) di Contentful . Kami tidak menggunakan fitur terjemahannya, tetapi kami mendapat satu ruang (semacam proyek atau folder) per bahasa. Kami menggunakan plugin gatsby-source-contentful untuk mengambil data ini, namun, sebelumnya kami mengambil dan mengonversi data ini ke file JSON sendiri dan menggunakan plugin gatsby-source-filesystem (kami menggunakan struktur folder seperti /en/blog/... , /de/blog/... ), jadi tidak masalah jika seseorang menggunakan Contentful atau tidak, selama setiap node mengetahui lokalnya.

Kami juga memiliki beberapa teks seperti label tombol, beberapa tautan atau konten statis yang tidak berasal dari Contentful, tetapi diterjemahkan dalam Transifex dan disinkronkan ke file JSON yang disimpan dalam repo. Untuk bagian ini kami perlu menggunakan beberapa perpustakaan i18n dan memutuskan untuk menggunakan react-intl , hanya karena saya sudah mengetahuinya dan saya tahu itu menangani pemformatan tanggal dan angka juga. Berikut cara kami menyiapkannya: https://github.com/gatsbyjs/gatsby/issues/3830#issuecomment -362710469. Kami kemudian menggunakan misalnya intl.formatMessage ketika membuat tag meta dan komponen <FormattedMessage /> , <FormattedDate /> dll dalam template.

@szimek Jika saya memahami Anda dengan benar maka Anda memiliki react-intl menangani terjemahan teks komponen saat posting berada di rute hardcoded di bawah direktori pages?

Itu berarti bahwa rute yang di-hardcode adalah satu-satunya yang dirender secara statis? Dan terjemahan antar komponen i18n dirender secara dinamis?

@deltaskelta Saya tidak yakin saya mengerti pertanyaan Anda.

Kami tidak memiliki perutean sisi klien khusus (seperti yang dijelaskan misalnya di sini ) saat ini, hanya halaman yang dibuat secara statis. Saat membuat halaman post (kami juga membuat halaman index dan category khusus lokal dan paginasi menggunakan versi plugin gatsby-pagination sedikit dimodifikasi), kami menggunakan kode berikut:

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,
    },
  });
});

Bahkan jika Anda menonaktifkan JS, semua konten, termasuk tag meta, dirender dalam bahasa yang benar.

Di pihak kami, kami menggunakan i18next dengan beberapa penyesuaian

Prinsip utamanya adalah sebagai berikut:

  • Lokal tersedia sebagai file .json dan cukup dipindahkan ke direktori /dist/ selama pembuatan.
  • Kami sedang mengerjakan satu halaman yang akan menghasilkan versi statis sebanyak bahasa yang kami miliki, menggunakan onCreatePage (dalam gatsby-node.js ).
  • Informasi halaman (misalnya nama path) dipusatkan dalam satu file.

Lokal

Terjemahan sebagian besar dikelompokkan berdasarkan halaman, dengan satu namespace (= file JSON) per halaman + satu file global (untuk teks bersama seperti header/footer).

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

Sayangnya, tidak ada hot-reload pada modifikasi lokal

i18berikutnya

i18next diinisialisasi dengan konfigurasi berikut:

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);
}

Informasi halaman

Sebelum membuat semua versi i18n dari halaman kita, kita perlu mengetahui beberapa informasi yang kita kelompokkan dalam file 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...

Dimana kunci adalah nama file halaman , dan ruang nama adalah nama file lokal . Mereka bisa berbeda

Pada kasus ini:

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

Dan di mana path adalah nama path dari versi (bahasa) halaman kami yang akan datang.

Buat halaman

Dengan contoh yang sama seperti di atas, tujuan kami di sini adalah membangun versi FR + EN dari halaman rumah dan proyek.

Untuk mewujudkannya, kami membuat fungsi khusus:

/**
 * 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];
}

Helper ini kemudian akan digunakan selama hook onCreatePage , memilih setiap halaman melalui regex:

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();
  });
}

Kami sekarang memiliki dua versi setiap halaman, dengan nama jalur khusus (dari file informasi halaman kami). Anda mungkin memperhatikan bahwa kami meneruskan informasi language ke setiap halaman melalui pathContext . Nilai ini akan digunakan pada setiap halaman untuk menampilkan bahasa yang tepat.

Tampilkan bahasa yang tepat

Kami menggunakan kelas React untuk halaman, dengan dekorator berikut secara otomatis mengetahui bahasa halaman saat ini dan memperbarui i18n jika diperlukan:

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} />;
      }

    }
  );

}

Kemudian panggil di halaman:

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

Pfew, yang harus Anda lakukan sekarang adalah menggunakan fungsi translate dari i18next.

Kesimpulan

👍 Satu file sumber yang menghasilkan versi sebanyak yang diperlukan selama pembuatan
👍 Manajemen keluaran halaman yang mudah
👍 Beberapa upaya pada awalnya, tetapi kemudian semuanya menjadi sederhana

Tidak ada hot-reload untuk lokal

Saya merasa itu bukan "jalan hidup yang statis" ... Tapi itulah yang terbaik yang berhasil kami dapatkan untuk saat ini.

Saya akan senang melihat pendapat Anda tentang ini, dan bagaimana Anda mengelola ini.

PS. Poke @szimek , itulah yang ingin saya tunjukkan kepada Anda beberapa hari yang lalu :)

Saya telah menggunakan @angeloocana https://github.com/angeloocana/gatsby-plugin-i18n + React-intl dan itu tidak serumit metode di atas, tetapi ada beberapa batasan (lihat masalah repo) dan saya tidak begitu senang dengan React-intl. ingin mencoba https://github.com/lingui/js-lingui @ tricoder42 , hanya belum sempat.

@monsieurnebo apa tujuan menjalankan deletePage tepat sebelum createPage ? Saya suka solusi Anda dan saya telah mencoba menerapkannya, tetapi saya memiliki beberapa kesalahan.

  • Saya salah mendapatkan pathContext.language tanpa menggunakan deletePage

  • atau saya mendapatkan kesalahan build ketika saya memasukkan deletePage seperti contoh Anda. (disebutkan TypeError: Cannot read property 'id' of undefined ketika build mencapai tahap run graphql queries )

Ini adalah solusi terbaik yang saya lihat sejauh ini.

@deltaskelta Senang melihat Anda menyukainya!

deletePage digunakan untuk membatalkan pembuatan halaman default oleh Gatsby. Jika Anda tidak menambahkan ini, Anda akan mendapatkan halaman kustom Anda, dan halaman default.

Periksa direktori public dengan dan tanpa baris ini, Anda akan melihat perbedaannya ;)

Tentang kesalahan Anda, sulit ditebak tanpa kode. Bisakah Anda membuat repositori dengan kode Anda? Saya akan melihatnya kemudian.

EDIT: Apakah Anda tertarik dengan contoh ?

Oh itu tidak terkait dengan panggilan deletePage. Itu adalah masalah tidak menyalin objek halaman karena saya telah memodifikasi contoh Anda. Saya selalu tersandung dengan menyalin objek setelah jauh dari js untuk sementara waktu ;)

@monsieurnebo Saya telah bermain-main dengan solusi Anda dan tampaknya Anda masih memerlukan javascript untuk memuat lokal dari file json apakah itu benar? Selain itu tampaknya semua komponen yang dibungkus dengan react-i18next HOC memerlukan javascript untuk merender apa pun di komponen...

Bisakah Anda mengonfirmasi apakah ini cara kerjanya di pihak Anda?

EDIT: btw Saya melewatkan penyebutan Anda tentang sebuah contoh, jika Anda punya waktu, saya ingin melihat contoh lengkapnya.

@deltaskelta saya akan membuat contoh ketika saya punya waktu luang :)

@monsieurnebo dapatkah Anda mengonfirmasi bahwa metode Anda tidak secara statis merender string ke dalam html dan memerlukan javascript?

Yup, itu sebabnya itu bukan "cara hidup statis" sepenuhnya

Saya akan menyukai plugin yang menghasilkan teks statis sebagai gantinya.

hm saya melihat. Render statis akan menjadi cara yang harus saya lakukan...

Saya berpikir, karena konteksnya sudah diteruskan dengan nama bahasa untuk sebagian besar halaman di gatsby-node maka tidak akan terlalu sulit untuk hanya meminta kunci pesan mereka di kueri graphql untuk setiap halaman dan meneruskannya dengan cara itu, tetapi saya lebih suka menggunakan alat i18n sepenuhnya jika memungkinkan ...

@szimek bagaimana react-intl merender terjemahan pada langkah build dan tidak menggunakan js apa pun?

Seperti yang disebutkan, sejauh yang saya bisa lihat Gatsby-plugin-i18n menghasilkan teks statis. Apakah Anda memeriksa contohnya?

@deltaskelta Yah, semua terjemahan tersedia selama waktu pembuatan (itulah sebabnya saya menggunakan beberapa tata letak), jadi "hanya berfungsi" ™️ ;) Saya hanya berharap itu terus berfungsi di v2... Saya dapat menyiapkan aplikasi sampel jika Anda ingin. Saya belum benar-benar melihat ke gatsby-plugin-i18n , karena saya bekerja dengan Contentful, bukan file.

Saya belum membaca detailnya tetapi ada diskusi (atau lebih tepatnya monolog) tentang gatsby-plugin-i18n + kombo yang memuaskan di sini: https://github.com/angeloocana/gatsby-plugin-i18n/issues/31

@szimek Saya akan sangat tertarik dengan contoh. @sedubois Saya tahu gatsby-plugin-i18n juga menghasilkan teks statis tetapi saya tidak melihat di mana keajaiban terjadi yang hilang di i18next untuk menghasilkan file yang benar-benar statis ....

Saya pikir saya mungkin mengerti mengapa sekarang...apakah Anda meneruskan react-intl pesan melalui pathContext di gatsby-node selama render?

EDIT: jika ini masalahnya (yang masuk akal), maka pustaka i18n yang digunakan "agak" tidak relevan karena seseorang meneruskan pesan melalui konteks dan merender secara statis yang merupakan pengaturan gatsby murni dan lib i18n hanya menangani kasus khusus seperti tanggal dan jamak dengan js.

Setelah pengujian lebih lanjut dari i18next dan react-intl tampaknya HOC terjemahan dari i18next memerlukan javascript untuk memuat, jadi meskipun pesan diteruskan melalui konteks dan dirender secara statis, setiap penggunaan terjemahan HOC akan membuat seluruh komponen membutuhkan javascript untuk dijalankan.

Komponen react-intl FormattedMessage , di sisi lain, merender pesan default (yang dapat didasarkan pada konteks yang diteruskan ke sana) dan merender secara statis ke dalam html saat build.

Secara desain, saya akan berpikir bahwa integrasi i18n yang lebih alami adalah dengan react-intl jika Anda ingin mencapai terjemahan yang dirender secara statis dalam HTML. Jika saya salah memahami aliran yang kalian gunakan, mohon perbaiki saya

@mattferderer punya ide yang tepat di sini, tapi saya pikir itu perlu sedikit penyesuaian. https://github.com/gatsbyjs/gatsby/issues/3830#issuecomment -362715706

tata letak dirender sebelum halaman, jadi tanpa membuat banyak tata letak, tidak ada cara untuk menyampaikan pesan melalui konteks, dari fungsi createPages (koreksi saya jika saya salah di sini). Jadi, untuk membuat i18n termudah, saya akan berpikir bahwa tata letak hanya memanggil children() dan kemudian tata letak yang berbeda per efek bahasa akan dicapai dengan meminta gatsby-node membuat jalur per bahasa yang berbeda halaman indeks dari pages/index yang dapat menyampaikan pesan melalui konteks

EDIT: maaf untuk mengoceh tetapi semuanya menjadi jelas dan saya harus merekamnya di suatu tempat

EDIT2: Saya pasti salah di atas, header dan footer harus masuk dalam tata letak, saya hanya tidak tahu bagaimana cara menyampaikan pesan kepada mereka tanpa membuat banyak tata letak. Satu-satunya cara lain yang dapat saya pikirkan adalah dengan memisahkan url dan regexing untuk lokal...

@KyleAMathews dengan v2 hanya memiliki satu tata letak, bagaimana kita bisa meneruskan data seperti pesan i18n ke komponen tata letak root melalui konteks berdasarkan jalur atau larik kunci bahasa?

Jika ini dapat dilakukan, maka akan mudah untuk mengimplementasikan i18n, tetapi saya tidak dapat melihat bagaimana melakukannya tanpa membuat banyak tata letak

@deltaskelta Berikut adalah contoh dari apa yang kami lakukan: https://github.com/szimek/gatsby-react-intl-example. Ini menunjukkan cara merender posting individual, cara menghasilkan halaman indeks untuk setiap lokal, cara menggunakan komponen react-intl , cara menggunakan react-intl injectIntl HOC untuk menetapkan judul (atau tag meta lainnya) untuk halaman indeks menggunakan intl.formatMessage helper dll.

Halaman yang dihasilkan adalah:

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

Di aplikasi sebenarnya kami menggunakan versi modifikasi dari gatsby-pagination , karena versi aslinya tidak mendukung opsi tata letak. Kami juga menyetel bidang post_id untuk setiap kiriman yang memungkinkan kami menemukan terjemahan kiriman yang sama, misalnya dalam kasus aplikasi demo ini, kedua kiriman akan memiliki post_id .

OMONG-OMONG. Saya baru menyadari bahwa kemungkinan besar kami perlu membuat peta situs terpisah untuk setiap bahasa, sehingga Swiftype (mesin telusur yang kami gunakan) tahu halaman apa yang kami dapatkan.

@deltaskelta secara singkat Anda akan memiliki komponen halaman untuk setiap bahasa dan kemudian memiliki komponen tata letak per bahasa. Inilah salah satu cara Anda bisa melakukan ini.

// 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

@KyleAMthews File-file ini adalah templat, bukan? Apakah ini berarti jika saya memiliki 3 jenis halaman dan 7 bahasa, saya memerlukan 21 template? :)

Di atas adalah cara yang paling optimal untuk melakukannya. Jika setiap komponen tata letak tidak terlalu berbeda, Anda dapat menggabungkannya menjadi satu komponen tata letak, lalu beralih tata letak bergantung pada bahasa yang aktif.

Saya belum membaca detailnya tetapi ada diskusi (atau lebih tepatnya monolog) tentang gatsby-plugin-i18n + kombo yang memuaskan di sini: angeloocana/gatsby-plugin-i18n#31

@sedubois , haha, ya. Ringkasan: membuatnya berfungsi dan menyertakan repo pemula gatsby-starter-contentful-i18n di dokumen Gatsby melalui PR ini: https://github.com/gatsbyjs/gatsby/pull/4138

Tertarik dengan solusi lain di atas, terutama bagaimana membandingkannya dengan plugin komunitas re: SEO, dll.

@mccrodp Solusi Anda terlihat sangat mirip dengan saya, perbedaan utamanya adalah gatsby-plugin-i18n tidak mengharuskan Anda untuk secara eksplisit meneruskan opsi layout ke createPage , tetapi melakukannya untuk Anda di balik layar. Namun, masih menggunakan banyak tata letak;)

Saya telah mengikuti saran @KyleAMthews dan membuat components/Layout yang menggunakan lib i18n dan menghapus folder tata letak gatsby saya sepenuhnya. Dengan cara ini, di gatsby-node saya dapat membuat halaman untuk lokal saya dan mereka memiliki akses ke semua halaman yang dapat diakses, termasuk jalur.

Saya kemudian dapat meneruskan lokal langsung ke komponen tata letak yang meneruskannya ke i18n.

Agak merepotkan jika harus membungkus setiap komponen tingkat halaman dengan tata letak, tetapi itu telah menghilangkan begitu banyak kebingungan dan sangat menyederhanakan kode saya.

Hai @deltaskelta , apakah Anda punya contoh solusi Anda? Akan senang melihat apakah ada yang bisa dipelajari darinya untuk mendorong upstream ke plugin komunitas i18n. Terima kasih.

seluruh proyek saya dalam keadaan berantakan sekarang, tetapi saya pikir saya dapat menjelaskan dasar-dasarnya ...

  1. Tidak ada tata letak - karena (jika saya ingat dengan benar), tata letak berperan sebelum jalur atau hal lain yang sangat penting, yang mencegah saya memberikan objek pesan yang tepat...

  2. Beri makan messages dan locale di gatsby-node melalui konteks...

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. Sekarang buat komponen tata letak global yang perlu dipanggil pada setiap komponen tingkat halaman...
// 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. Panggil komponen tata letak global dengan komponen tingkat halaman Anda yang memiliki lokal yang tepat dan pesan yang diteruskan dari konteks
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>
  );
};

Saya harus membersihkan dan mengatur ulang kode ini karena saya baru saja melakukannya dengan cepat untuk membuktikan bahwa itu bisa berhasil dan saya akan mengunjunginya kembali nanti...Saya harap ini memberi Anda intinya

Saya membuat starter gatsby yang menggunakan js-lingui untuk menerjemahkan pesan:
https://github.com/dcroitoru/gatsby-starter-i18n-lingui

Di aplikasi sebenarnya kami menggunakan versi gatsby-pagination yang dimodifikasi, karena versi aslinya tidak mendukung opsi tata letak. Kami juga menyetel bidang post_id untuk setiap posting yang memungkinkan kami menemukan terjemahan dari posting yang sama, misalnya dalam kasus aplikasi demo ini, kedua posting akan memiliki post_id yang sama.

@szimek apakah ada kemungkinan Anda bisa membagikan gatsby-pagination Anda yang dimodifikasi? Saya akan sangat tertarik untuk melihatnya karena saya sendiri mengalami masalah serupa.

@martynhoyer Patch saya telah digabungkan, jadi saya beralih kembali ke versi asli gatsby-pagination . Masalah apa yang Anda alami?

Hai @sgoudie
Saya menggunakan tutorial ini: https://www.gatsbyjs.org/blog/2017-10-17-building-i18n-with-gatsby/ tetapi saya tidak dapat menemukan locales/{lang}/*.json . Apakah ada yang punya petunjuk?
2018-04-25 12_04_13-o intermedium agora e banco inter

Konfigurasi saya:
gasbty-node.js
```javascriptexports.onPostBuild = () => {
console.log('Menyalin lokal')
fs.copySync(
path.join(__dirname, '/src/locales'),
path.join(__dirname, '/public/locales')
)
}

```

Menambahkan

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

ke gatsby-node.js

@ThiagoMiranda Saya menghadapi masalah yang sama kemudian saya menyadari bahwa gatsby develop tidak memanggil onPostBuild, hanya gatsby build memanggilnya. onPostBootstrap dipanggil setiap kali.

Adakah yang tahu cara membuat https://moz.com/learn/seo/hreflang-tag di tata letak?

@RobinHerzog Kami membuatnya dalam templat menggunakan Helm. Mereka khusus untuk jenis halaman, jadi setidaknya dalam kasus kami tidak masuk akal untuk membuatnya dalam tata letak.

@szimek terima kasih atas balasannya. Saya mengerti tetapi dalam kasus saya akan menarik untuk memilikinya di tata letak.

<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" />

Untuk saat ini, seperti yang Anda katakan, salin baris-baris itu di setiap templat.

Saya baru mulai mengembangkan dengan React/JavaScript tetapi semua yang saya lihat untuk mendukung i18n terlalu rumit. Ini adalah karya saya sendiri untuk penggunaan yang paling umum: pemula yang bijaksana

Live reload, SEO friendly, dan bahasa Default tidak menggunakan kunci di url.
Semua halaman .js dibuat untuk semua bahasa.
Semua tata letak dan .md harus dibuat untuk semua bahasa untuk mencegah kesalahan.
Komponen LangSelect dan Link adalah i18n smart.

Jika Anda dapat membantu saya dan menjelaskan kepada saya bagaimana saya dapat meningkatkan kode dan gaya saya, saya akan berterima kasih.

@ Tom-Pichaud, saya percaya bahwa karena Anda tidak meneruskan pesan ke komponen halaman, mereka tidak akan dirender secara statis di sana.

Pengaturan penurunan harga i18n di gatsby-node terlihat mirip dengan apa yang telah dilakukan orang-orang di sini, tetapi saya ingin tahu apakah rendering statis dengan javascript dinonaktifkan pada komponen halaman Anda?

Ya, saya memang mendapatkan rendering statis, itulah tujuan saya, i18n-react lakukan triknya!

@TomPichaud apakah mungkin bagi Anda untuk membagikan bagaimana i18n-react yang Anda sebutkan lebih baik daripada js-lingui ?

Satu hal yang tidak saya mengerti adalah kebutuhan aktual untuk paket eksternal untuk memuat pesan yang diterjemahkan (selain pluralisasi dan kerabat, mungkin).

Untuk situs sederhana dengan konten statis, saya hanya menduplikasi halaman untuk setiap bahasa onCreatePage dan meneruskan lokal ke 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()
  })
}

Kemudian, pada halaman sebenarnya, saya menggunakan lokal dalam konteks untuk menanyakan konten menggunakan filter graphql.

Katakanlah saya memiliki konten rumah di /data/home/en.js dan /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

berfungsi dengan baik dengan netlifyCMS (walaupun agak bertele-tele hingga mendukung i18n) dan gambar dalam file JSON (kita perlu membuat NodeField baru dengan jalur relatif sehingga sistem file Gatsby mendapatkannya)

Bukankah ini cukup untuk kebanyakan kasus?

Saya masih menguji dan belum menggunakan semua ini dalam produksi, tetapi saya berpikir untuk menggunakan API konteks reaksi untuk lokal untuk menyelesaikan beberapa masalah yang tertunda seperti tautan yang dilokalkan

@pbrandone Ini tampaknya menjadi pendekatan yang bagus untuk saya. Saya pikir sesuatu yang serupa harus didokumentasikan secara resmi.

Terima kasih atas semua masukannya, jumlah ide yang dibahas di sini dengan jelas menandai permintaan akan dukungan i18n yang terdokumentasi dengan baik.

@pbrandone Apakah itu berarti Anda harus secara eksplisit menentukan semua kunci yang digunakan oleh komponen anak apa pun di IndexPage dalam kueri ini dan meneruskan terjemahan ke semua komponen melalui alat peraga?

Juga, saya menggunakan aturan pluralisasi dan tanggal relatif, jadi saya tetap harus memuat data spesifik lokal tambahan :/

Namun, saya setuju bahwa akan sangat bagus untuk memiliki dokumentasi resmi bagaimana melakukan i18n tanpa perpustakaan apa pun untuk kasus-kasus sederhana dan kemudian bagaimana melakukannya dengan perpustakaan paling populer.

@szimek baik, dalam hal ini ya.

Sangat mudah untuk menambahkan react-intl (atau perpustakaan i18n lainnya) tho:

// 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

dan kemudian di halaman:

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

Tapi kemudian Anda tidak akan dapat menggunakan beberapa file JSON (misalnya per halaman), atau memiliki semua data CMS dalam file tersebut untuk kueri dan transformasi dengan kekuatan graphql.
Dengan pendekatan graphql kita dapat, misalnya, memiliki beberapa kunci dengan jalur untuk gambar dalam file JSON tersebut untuk memuat gambar yang berbeda per lokal dan masih dapat menggunakan gatsby-image pada mereka.
Dan kemudian tambahkan CMS netlify untuk mengedit file JSON itu

Belum melihat gatsby v2 dengan benar tetapi tampaknya ada komponen StaticQuery yang memungkinkan kami untuk menanyakan komponen anak (seseorang mengoreksi saya jika saya salah!)

Jika itu masalahnya, kita bisa membuat React Context untuk membuat lokal tersedia di mana saja dan kemudian menanyakan kunci yang diperlukan di setiap komponen dengan pemfilteran lokal

@pbrandone Anda benar, itu secara statis membuat seperti itu. Saya ingat mengujinya di masa lalu dan gagal, tetapi itu sebelum saya memiliki pemahaman yang baik tentang cara kerja gatsby, saya mungkin telah menyiapkan react-intl di browser gatsby yang sepertinya tidak dapat dirender tanpa javascript. Solusi saya sekarang terlihat seperti milik Anda

@KyleAMathews Saya mencoba memperbarui halaman kami ke Gatsby ke v2 dan memiliki masalah dengan penyiapan react-intl dan kueri graphql kami.

Saya sebelumnya menjelaskan bagaimana saya menggunakan tata letak khusus bahasa untuk memuat data bahasa di Gatsby v1 - https://github.com/szimek/gatsby-react-intl-example. Di Gatsby v2 saya punya ide untuk mengganti tata letak ini dengan komponen halaman khusus bahasa. Aku harus bahasa-agnostik src/templates/Post.js komponen dan kemudian komponen bahasa-spesifik seperti src/templates/Post.en.js , src/templates/Post.de.js bahwa hanya akan memuat data bahasa dan membuat komponen bahasa-agnostik.

Dalam komentar Anda sebelumnya (https://github.com/gatsbyjs/gatsby/issues/3853#issuecomment-367115380) Anda menunjukkan contoh di mana setiap komponen halaman memiliki kueri khusus bahasa.

Masalahnya adalah ketika memanggil createPage , saya memberikan nama komponen khusus bahasa ini (misalnya src/templates/Post.en.js ) sebagai opsi component , tetapi kueri graphql ada di komponen language-agnostic, karena __persis sama untuk semua bahasa__ (tergantung pada locale , tapi saya meneruskannya di context ). Saya ingin menghindari pengulangan kueri yang persis sama di semua komponen khusus bahasa ini.

Ada ide bagaimana mengatasinya? Bisakah saya mengekstrak kueri ini ke variabel? Ketika saya mencobanya, Gatsby mengeluh tentang nama kueri dan fragmen yang sama ...

Saya baru-baru ini menambahkan starter Gatsby default dengan fitur rute url multi-bahasa dan deteksi bahasa browser. (demo)

gatsby-starter-default-intl

Fitur:

  • Lokalisasi (Multibahasa) disediakan oleh react-intl .

  • Pengalihan otomatis berdasarkan bahasa pilihan pengguna di browser yang disediakan oleh browser-lang .

  • Mendukung rute url multi-bahasa dalam satu komponen halaman. Itu berarti Anda tidak perlu membuat halaman terpisah seperti pages/en/index.js atau pages/ko/index.js .

  • Berdasarkan gatsby-starter-default dengan sedikit modifikasi.

@wiziple Terima kasih! Ini terlihat sangat menarik. Saya tidak tahu Anda dapat melakukan sesuatu seperti ini: https://github.com/wiziple/gatsby-starter-default-intl/blob/master/src/i18n/withIntl.js#L38 ;) Semoga masih berfungsi di Webpack 4...

Apakah mungkin memuat data lokal dengan cara yang sama di sini https://github.com/wiziple/gatsby-starter-default-intl/blob/master/src/i18n/withIntl.js#L6 ? Kami mendukung 6 (segera 7 bahasa), jadi akan sangat bagus jika saya hanya dapat memuat bahasa yang saya buat untuk halaman tersebut. bukan masalah besar jika tidak memungkinkan - untungnya, file data lokal ini relatif kecil.

Saya juga harus melihat bagaimana Anda menghasilkan halaman-halaman ini, karena dalam kasus saya tidak setiap halaman diterjemahkan ke dalam semua bahasa (tidak ada satu bahasa "sumber"), jadi solusi dengan onCreatePage mungkin tidak akan berfungsi dalam hal ini.

Mudah-mudahan, ini akan menyelesaikan masalah saya dengan kueri graphql yang sama di setiap komponen halaman khusus bahasa.

@szimek
Website yang saya kelola memiliki 14 bahasa dan setiap file bahasa berukuran 12-15 KB. Saya cukup yakin kita perlu menyediakan bahasa yang tepat untuk setiap router bahasa pada waktu pembuatan untuk menghasilkan data SEO. Jadi saya tidak yakin bagaimana saya bisa menangani ini tanpa menyediakan semua bahasa.

Saya mengerti bahwa terkadang sulit untuk menyediakan setiap halaman yang diterjemahkan ke dalam semua bahasa. Anda mungkin dapat menyelesaikan ini dengan memberikan beberapa pengecualian pada onCreatePage di gatsby-node.js . Dalam kasus saya, saya hanya menyelesaikan dengan tidak menawarkan bahasa terjemahan terlepas dari router bahasa. Anda dapat menemukan situs web showcase pada produksi dari README.md starter dan memeriksa kinerjanya.

@wiziple Terima kasih banyak!

Saya menggunakan Anda withIntl komponen dengan dinamis require trik untuk terjemahan (saya tidak tahu apakah ada kerugian untuk menggunakan itu) dan tampaknya besar pekerjaan. Ini memecahkan masalah yang saya perjuangkan - cara menangani kueri graphql yang sama dalam beberapa komponen halaman khusus bahasa - dengan memiliki satu komponen halaman untuk semua bahasa.

@wiziple terima kasih atas share

lingui tampaknya menjadi alternatif yang lebih baik . Saya tidak berpikir @dcroitoru mendapat pengakuan yang tepat untuk contoh yang bagus. Hanya perlu sedikit cinta untuk mendorongnya ke Gatsby 2.0

Saya setuju bahwa Lingui memang sangat bagus, meskipun masih membutuhkan starter yang lengkap, dengan versi terbaru dari Gatsby tetapi juga Lingui. Starter yang disebutkan tidak resmi dan kehilangan beberapa fitur terakhir kali saya memeriksa (misalnya menggunakan loader untuk menjalankan kompilasi lingui dengan cepat). Penulis Lingui @tricoder42 mengatakan bahwa dia akan memberikan dokumentasi saat Lingui v3 keluar (yang tampaknya akan segera dirilis ).

NB: Saya perhatikan bahwa kebutuhan saya akan perpustakaan i18n berkurang setelah mengintegrasikan CMS (DatoCMS), tetapi saya masih membutuhkan Lingui untuk beberapa string yang tidak menemukan tempatnya di CMS dan juga untuk pluralisasi dan mungkin hal-hal lain nanti jadi saya pasti ingin menyimpannya di basis kode saya.

Bagaimanapun dalam kasus saya keberadaan gatsby-plugin-i18n membuat hal-hal cukup membingungkan karena tidak dipelihara, memiliki nama yang membingungkan, dan menarik perhatian dari solusi lain yang sangat bagus seperti js-lingui dan CMS yang kemudian saya ambil sambil mencari tahu dan berkumpul bersama.

Saya telah membuat dua contoh internasionalisasi dengan integrasi react-intl

Contoh pertama difokuskan pada bundling hanya terjemahan saat ini dalam potongan js (sesuatu yang tidak dapat saya temukan di plugin lain yang saya periksa).

Contoh kedua berfokus pada penggunaan kueri dinamis untuk menyediakan hanya terjemahan yang diminta untuk kombinasi halaman/bahasa tertentu.

Semoga contoh ini bermanfaat bagi seseorang.

Juga membuat posting menengah cepat (dan lupa mempostingnya di sini) dengan cukup banyak apa yang ada di https://github.com/gatsbyjs/gatsby/issues/3853#issuecomment -395432693 (walaupun sedikit lebih mendalam).

https://blog.significa.pt/i18n-with-gatsby-528607b4da81 untuk siapa saja yang tertarik

Masalah lama akan ditutup setelah 30 hari tidak aktif. Masalah ini telah diam selama 20 hari dan ditandai sebagai basi. Balas di sini atau tambahkan label "tidak basi" agar masalah ini tetap terbuka!

Hai guys udah hampir setahun

Saya baru-baru ini merilis plugin gatsby baru gatsby -plugin-intl yang dengan mudah menjadikan situs web gatsby Anda sebagai kerangka internasionalisasi di luar kotak.

DEMO: https://gatsby-starter-default-intl.netlify.com

  • Kerangka internasionalisasi luar biasa yang didukung oleh react-intl

  • Mendukung pengalihan otomatis berdasarkan bahasa pilihan pengguna di browser

  • Mendukung rute url multi-bahasa dalam satu komponen halaman. Ini berarti Anda tidak perlu membuat halaman terpisah seperti pages/en/index.js atau pages/ko/index.js .

  • Seperti yang disarankan beberapa dari kalian di atas, sekarang hanya menggabungkan bahasa saat ini selama waktu pembuatan.

Juga, saya ingin menyebutkan bahwa banyak contoh/pemula i18n sebenarnya dirender di sisi klien. Cara terbaik untuk memeriksa apakah aplikasi dirender sebagai SSR adalah dengan melihat kode sumber dan memeriksa apakah ada teks yang dilokalkan. Harap periksa kembali masalah ini ketika Anda menginternasionalkan situs web gatsby Anda untuk SEO.

Hai guys udah hampir setahun

Saya baru-baru ini merilis plugin gatsby baru gatsby -plugin-intl yang dengan mudah menjadikan situs web gatsby Anda sebagai kerangka internasionalisasi di luar kotak.

DEMO: https://gatsby-starter-default-intl.netlify.com

  • Kerangka internasionalisasi luar biasa yang didukung oleh react-intl
  • Mendukung pengalihan otomatis berdasarkan bahasa pilihan pengguna di browser
  • Mendukung rute url multi-bahasa dalam satu komponen halaman. Ini berarti Anda tidak perlu membuat halaman terpisah seperti pages/en/index.js atau pages/ko/index.js .
  • Seperti yang disarankan beberapa dari kalian di atas, sekarang hanya menggabungkan bahasa saat ini selama waktu pembuatan.

Juga, saya ingin menyebutkan bahwa banyak contoh/pemula i18n sebenarnya dirender di sisi klien. Cara terbaik untuk memeriksa apakah aplikasi dirender sebagai SSR adalah dengan melihat kode sumber dan memeriksa apakah ada teks yang dilokalkan. Harap periksa kembali masalah ini ketika Anda menginternasionalkan situs web gatsby Anda untuk SEO.

Hai @wiziple terima kasih banyak untuk itu, saya menjadi gila mencari solusi untuk melokalkan Gatsby.
Mungkin saya tidak mengerti maksudnya tetapi, apakah Anda memiliki SEMUA string bahasa hanya dalam satu file?
Apakah mungkin untuk membagi JSON setiap bahasa menjadi lebih banyak file, mungkin menggunakan struktur komponen yang sama?

@ cant89 Saya mengerti maksud Anda, tetapi saat ini tidak mungkin tanpa mengubah kode plugin. Atau Anda dapat membuat skrip yang mem-parsing direktori src dan mengambil semua file bahasa komponen. Gabungkan menjadi satu JSON lalu kaitkan ke gatsby develop atau gatsby build .
Setelah Anda mendapatkan semua file JSON dan digabungkan sebagai objek bersarang, Anda juga dapat mengonversinya sebagai objek rata.
https://github.com/yahoo/react-intl/wiki/Upgrade-Guide#flatten -messages-object

Kami memiliki contoh pengaturan yang bagus untuk i18n. https://github.com/gatsbyjs/gatsby/tree/master/examples/using-i18n. Kami tidak benar-benar memiliki pendapat tentang kerangka kerja i18n. Pilih saja satu sesuai dengan keinginan Anda.

Kami memiliki contoh pengaturan yang bagus untuk i18n. https://github.com/gatsbyjs/gatsby/tree/master/examples/using-i18n. Kami tidak benar-benar memiliki pendapat tentang kerangka kerja i18n. Pilih saja satu sesuai dengan keinginan Anda.

Keren, terima kasih, saya akan mencoba!
Lagi pula tautan pada readme rusak, mungkin maksud Anda https://using-i18n.netlify.com/ ?

@wardpeet Apakah contoh Anda menghasilkan string terjemahan statis (pada waktu pembuatan)? Atau apakah itu menghasilkan teks selama runtime?

@monsieurnebo sepertinya waktu pembuatan

@cant89 kami masih memperbarui dns jadi segera naik menggunakan-i18n.netlify.com/ adalah tautan yang benar.

@monsieurnebo saat ini sedang dibangun. Ini membuat salinan situs web Anda untuk setiap bahasa sehingga semuanya dapat dibuat secara statis. Ini berarti situs web Anda tetap cepat karena semuanya hanya .html.

tidak yakin di mana lagi untuk menanyakan ini tetapi sedikit relevan. apakah salah satu dari plugin ini mendukung pathPrefix gatsby?

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.

Hmm menarik, saya pikir yang pertama biasanya lebih masuk akal karena pathPrefix semacam membuat domain Anda menjadi domain.com/prefix jadi ubah root ketika Anda menginstal Gatsby di subdirektori, jika Anda tidak menginstalnya ke subdirektori Anda tidak membutuhkannya, jika Anda menggunakan subdirektori mengubah awalan menjadi setelah bahasa akan merusaknya ..

Sekarang muncul pertanyaan, mengapa Anda menggunakan pathPrefix sejak awal?

Ref: pathPrefix docs

Hai,

Sebagian besar diskusi di sini adalah tentang cara membuat situs gatsby. Tetapi ada perbedaan antara memiliki POC yang berfungsi, dan memiliki sistem siap produksi yang dioptimalkan.

Jika Anda tertarik untuk membaca lebih lanjut tentang pemecahan kode dan file i18n, dan mengapa sebagian besar solusi di utas ini tidak dioptimalkan, Anda akan menemukan masalah ini berguna

Apakah halaman ini membantu?
0 / 5 - 0 peringkat