작가:
    생성:2024-03-07마지막 업데이트:2026-06-23

    Intlayer로 Vite 및 React 번역하기 | 국제화(i18n)

    목차

    왜 다른 대안들 대신 Intlayer를 선택해야 하나요?

    react-i18next나 i18next와 같은 주요 솔루션과 비교했을 때, Intlayer는 다음과 같은 통합된 최적화 기능을 제공하는 솔루션입니다:

    Intlayer는 컴포넌트 수준의 콘텐츠 스코핑, 지연 로드(lazy-loaded) 번역, 그리고 국제화(i18n) 확장에 필요한 모든 기능을 제공하여 Vite 및 React와 완벽하게 작동하도록 최적화되어 있습니다.

    페이지에 방대한 JSON 파일을 로드하는 대신, 필요한 콘텐츠만 로드하세요. Intlayer는 번들 및 페이지 크기를 최대 50%까지 줄이는 데 도움을 줍니다.

    애플리케이션의 콘텐츠를 스코핑하면 대규모 애플리케이션의 유지보수가 용이해집니다. 전체 콘텐츠 codebase를 검토해야 한다는 심리적 부담 없이 단일 기능 폴더를 복제하거나 삭제할 수 있습니다. 또한, Intlayer는 콘텐츠의 정확성을 보장하기 위해 완벽한 타입 지정(fully typed)을 지원합니다.

    콘텐츠를 같은 위치에 배치(Co-locating)하면 대규모 언어 모델(LLM)에 필요한 문맥이 줄어듭니다. Intlayer는 또한 누락된 번역을 테스트하기 위한 CLI, LSP, MCP, 그리고 agent skills과 같은 도구 모음을 제공하여 AI 에이전트의 개발자 경험(DX)을 더욱 원활하게 만듭니다.

    AI 제공업체의 비용으로 원하는 LLM을 사용하여 CI/CD 파이프라인에서 번역을 자동화하세요. Intlayer는 또한 콘텐츠 추출을 자동화하는 컴파일러뿐만 아니라, 백그라운드에서 번역을 도와주는 웹 플랫폼을 제공합니다.

    방대한 JSON 파일을 컴포넌트에 연결하면 성능 및 반응성 문제가 발생할 수 있습니다. Intlayer는 빌드 타임에 콘텐츠 로딩을 최적화합니다.

    단순한 i18n 솔루션 그 이상으로, Intlayer는 자체 호스팅 가능한 시각적 편집기(visual editor)전체 CMS를 제공하여 다국어 콘텐츠를 실시간으로 관리할 수 있게 도와주며, 번역가, 카피라이터 및 기타 팀원과의 협업을 원활하게 만듭니다. 콘텐츠는 로컬 및/또는 원격으로 저장할 수 있습니다.


    대안보다 Intlayer를 선택해야 하는 이유는 무엇입니까?

    www.youtube.com
    ide.intlayer.org
    intlayer-vite-react-template.vercel.app

    'react-i18next' 또는 'i18next'와 같은 주요 솔루션과 비교할 때 Intlayer는 다음과 같은 통합 최적화가 제공되는 솔루션입니다.

    npm을 사용하여 필요한 패키지를 설치하세요:

    bash
    npx intlayer init --interactive
    
    --interactive 플래그는 선택 사항입니다. AI 에이전트인 경우 intlayer-cli init을 사용하세요.

    Intlayer는 구성 요소 수준 콘텐츠 범위 지정, 지연 로드 번역 및 국제화 확장(i18n)에 필요한 모든 기능을 제공하여 Vite 및 React와 완벽하게 작동하도록 최적화되었습니다.

    bash
    npm install intlayer react-intlayer
    npm install vite-intlayer --save-dev
    
    • intlayer 국제화 도구를 제공하는 핵심 패키지로, 설정 관리, 번역, 콘텐츠 선언, 트랜스파일레이션, 및 CLI 명령어를 포함합니다.

    • react-intlayer Intlayer를 React 애플리케이션과 통합하는 패키지입니다. React 국제화를 위한 context providers와 hooks을 제공합니다.

    • vite-intlayer Intlayer를 Vite bundler와 통합하기 위한 Vite 플러그인, 그리고 사용자의 선호 로케일 감지, 쿠키 관리, URL 리다이렉션 처리를 위한 미들웨어를 포함합니다.

    대용량 JSON 파일을 페이지에 로드하는 대신 필요한 콘텐츠만 로드하세요. Intlayer는 번들 및 페이지 크기를 최대 50% 줄이는 데 도움이 됩니다.

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    
    const config: IntlayerConfig = {
      internationalization: {
        locales: [
          Locales.ENGLISH,
          Locales.FRENCH,
          Locales.SPANISH,
          // 다른 로케일들
        ],
        defaultLocale: Locales.ENGLISH,
      },
    };
    
    export default config;
    
    이 구성 파일을 통해 로컬라이즈된 URL, 미들웨어 리디렉션, 쿠키 이름, 콘텐츠 선언의 위치 및 확장자, Intlayer 로그 비활성화 등을 설정할 수 있습니다. 사용 가능한 모든 매개변수의 전체 목록은 구성 문서를 참조하십시오.

    intlayer 플러그인을 구성에 추가하세요.

    vite.config.ts
    import { defineConfig } from "vite";
    import react from "@vitejs/plugin-react-swc";
    import { intlayer } from "vite-intlayer";
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [react(), intlayer()],
    });
    

    애플리케이션 콘텐츠의 범위를 지정하면 대규모 애플리케이션의 유지 관리가 용이해집니다. 전체 콘텐츠 코드베이스를 검토해야 하는 정신적 부담 없이 단일 기능 폴더를 복제하거나 삭제할 수 있습니다. 또한 Intlayer는 완전히 유형되어 콘텐츠의 정확성을 보장합니다.

    번역을 저장하기 위해 콘텐츠 선언을 생성하고 관리합니다:

    src/app.content.tsx
    import { t, type Dictionary } from "intlayer";
    import type { ReactNode } from "react";
    
    const appContent = {
      key: "app",
      content: {
        viteLogo: t({
          ko: "Vite 로고",
          en: "Vite logo",
          fr: "Logo Vite",
          es: "Logo Vite",
        }),
        reactLogo: t({
          ko: "React 로고",
          en: "React logo",
          fr: "Logo React",
          es: "Logo React",
        }),
    
        title: "Vite + React",
    
        count: t({
          ko: "카운트는 ",
          en: "count is ",
          fr: "le compte est ",
          es: "el recuento es ",
        }),
    
        edit: t<ReactNode>({
          ko: (
            <>
              <code>src/App.tsx</code>를 수정하고 저장하여 HMR을 테스트하세요
            </>
          ),
          en: (
            <>
              Edit <code>src/App.tsx</code> and save to test HMR
            </>
          ),
          fr: (
            <>
              Éditez <code>src/App.tsx</code> et enregistrez pour tester HMR
            </>
          ),
          es: (
            <>
              Edita <code>src/App.tsx</code> y guarda para probar HMR
            </>
          ),
        }),
    
        readTheDocs: t({
          ko: "Vite 및 React 로고를 클릭하여 자세히 알아보세요",
          en: "Click on the Vite and React logos to learn more",
          fr: "Cliquez sur les logos Vite et React pour en savoir plus",
          es: "Haga clic en los logotipos de Vite y React para obtener más información",
        }),
      },
    } satisfies Dictionary;
    
    export default appContent;
    
    콘텐츠 선언은 contentDir 디렉토리(기본값: ./src)에 포함되는 한 애플리케이션의 어느 곳에든 정의할 수 있습니다. 그리고 콘텐츠 선언 파일 확장자(기본값: .content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml})와 일치해야 합니다.

    콘텐츠를 같은 위치에 배치하면 LLM(대형 언어 모델)에 필요한 컨텍스트가 줄어듭니다. Intlayer에는 누락된 번역을 테스트하기 위한 CLI, LSP, MCPagent skills, AI 에이전트를 위한 개발자 경험(DX)을 더욱 원활하게 만듭니다.

    콘텐츠 파일에 TSX 코드가 포함되어 있다면, 콘텐츠 파일에 import React from "react";를 import하는 것을 고려해야 합니다.

    애플리케이션 전체에서 콘텐츠 사전에 접근하세요:

    src/App.tsx
    import { useState, type FC } from "react";
    import reactLogo from "./assets/react.svg";
    import viteLogo from "/vite.svg";
    import "./App.css";
    import { IntlayerProvider, useIntlayer } from "react-intlayer";
    
    const AppContent: FC = () => {
      const [count, setCount] = useState(0);
      const content = useIntlayer("app");
    
      return (
        <>
          <div>
            <a href="https://vitejs.dev" target="_blank">
              <img src={viteLogo} className="logo" alt={content.viteLogo.value} />
            </a>
            <a href="https://react.dev" target="_blank">
              <img
                src={reactLogo}
                className="logo react"
                alt={content.reactLogo.value}
              />
            </a>
          </div>
          <h1>{content.title}</h1>
          <div className="card">
            <button onClick={() => setCount((count) => count + 1)}>
              {content.count}
              {count}
            </button>
            <p>{content.edit}</p>
          </div>
          <p className="read-the-docs">{content.readTheDocs}</p>
        </>
      );
    };
    
    const App: FC = () => (
      <IntlayerProvider>
        <AppContent />
      </IntlayerProvider>
    );
    
    export default App;
    
    alt, title, href, aria-label 등과 같은 string 속성에서 콘텐츠를 사용하려면 함수의 값을 다음과 같이 사용할 수 있습니다:
    html
    <img src="{content.image.src.value}" alt="{content.image.value}" />
    <img src="{content.image.src.toString()}" alt="{content.image.toString()}" />
    <img src="{String(content.image.src)}" alt="{String(content.image)}" />
    
    useIntlayer 훅에 대해 더 알아보려면 문서를 참조하세요.

    AI 공급자의 비용으로 선택한 LLM을 사용하여 CI/CD 파이프라인을 번역하려면 자동화를 사용하세요. Intlayer는 또한 콘텐츠 추출을 자동화하는 컴파일러백그라운드에서 번역을 돕는 웹 플랫폼을 제공합니다.

    대규모 JSON 파일을 구성 요소에 연결하면 성능 및 반응성 문제가 발생할 수 있습니다. Intlayer는 빌드 시 콘텐츠 로딩을 최적화합니다.

    src/components/LocaleSwitcher.tsx
    import type { FC } from "react";
    import { Locales } from "intlayer";
    import { useLocale } from "react-intlayer";
    
    const LocaleSwitcher: FC = () => {
      const { setLocale } = useLocale();
    
      return (
        <button onClick={() => setLocale(Locales.English)}>
          언어를 영어로 변경
        </button>
      );
    };
    
    useLocale hook에 대해 자세히 알아보려면 documentation을 참조하세요.

    이 단계의 목적은 각 언어에 대한 고유한 경로를 만드는 것입니다. 이는 SEO 및 SEO 친화적인 URL에 유용합니다. 예시:

    -
    - https://example.com/ko/about
    - https://example.com/fr/about
    

    Intlayer는 단순한 i18n 솔루션 그 이상으로 관리에 도움이 되는 자체 호스팅 비주얼 편집기전체 CMS를 제공합니다. 다국어 콘텐츠를 실시간으로 제공하여 번역가, 카피라이터, 기타 팀원과 원활하게 협업할 수 있습니다. 콘텐츠는 로컬 및/또는 원격으로 저장될 수 있습니다.

    애플리케이션에 로컬라이제이션된 라우팅을 추가하려면 애플리케이션의 라우트를 래핑하고 로캘 기반 라우팅을 처리하는 LocaleRouter 컴포넌트를 만들 수 있습니다. 다음은 React Router를 사용한 예시입니다:

    src/components/LocaleRouter.tsx
    import { localeMap } from "intlayer"; // 'intlayer'의 유틸리티 함수 및 타입
    import type { FC, PropsWithChildren } from "react"; // 함수형 컴포넌트 및 props에 대한 React 타입
    import { IntlayerProvider } from "react-intlayer"; // 국제화 컨텍스트를 위한 Provider
    import { BrowserRouter, Route, Routes } from "react-router-dom"; // 네비게이션을 관리하기 위한 Router 컴포넌트
    
    /**
     * 로케일별 라우트를 설정하는 라우터 컴포넌트입니다.
     * React Router를 사용하여 네비게이션을 관리하고 로컬라이즈된 컴포넌트를 렌더링합니다.
     */
    export const LocaleRouter: FC<PropsWithChildren> = ({ children }) => (
      <BrowserRouter>
        <Routes>
          {localeMap(({ locale, urlPrefix }) => (
            <Route
              // 로케일(/en/, /fr/ 등)을 캡처하고 이후의 모든 경로와 일치하는 라우트 패턴
              path={`${urlPrefix}/*`}
              key={locale}
              element={
                <IntlayerProvider locale={locale}>{children}</IntlayerProvider>
              } // 로케일 관리를 위해 children을 래핑합니다
            />
          ))}
        </Routes>
      </BrowserRouter>
    );
    
    참고: routing.mode: 'no-prefix' | 'search-params'를 사용하는 경우, localeMap 함수를 사용할 필요가 없을 가능성이 높습니다.

    그러면 애플리케이션에서 LocaleRouter 컴포넌트를 사용할 수 있습니다:

    src/App.tsx
    import { LocaleRouter } from "./components/LocaleRouter";
    import type { FC } from "react";
    
    // ... Your AppContent component
    
    const App: FC = () => (
      <LocaleRouter>
        <AppContent />
      </LocaleRouter>
    );
    

    또한 intlayerProxy를 사용하여 애플리케이션에 서버 측 라우팅을 추가할 수 있습니다. 이 플러그인은 URL을 기반으로 현재 로케일을 자동으로 감지하고 적절한 로케일 쿠키를 설정합니다. 로케일이 지정되지 않은 경우, 플러그인은 사용자의 브라우저 언어 설정을 기반으로 가장 적절한 로케일을 결정합니다. 로케일이 감지되지 않으면 기본 로케일로 리다이렉트합니다.


    vite.config.ts
    import { defineConfig } from "vite";
    import react from "@vitejs/plugin-react-swc";
    import { intlayer } from "vite-intlayer";
    
    // https://vitejs.dev/config/
    export default defineConfig({
      plugins: [
        react(),
        intlayer({
          proxy: {
            ignore: (req) => req.url?.startsWith("/api"),
          },
        }),
      ],
    });
    
    1. 로케일이 변경될 때 URL 변경하기

      선택사항

      로케일이 변경될 때 URL을 변경하려면, useLocale 훅에서 제공하는 onLocaleChange 속성을 사용할 수 있습니다. 동시에, react-router-domuseLocationuseNavigate 훅을 사용하여 URL 경로를 업데이트할 수 있습니다.

      src/components/LocaleSwitcher.tsx
      import { useLocation, useNavigate } from "react-router-dom";
      import {
        Locales,
        getHTMLTextDir,
        getLocaleName,
        getLocalizedUrl,
      } from "intlayer";
      import { useLocale } from "react-intlayer";
      import { type FC } from "react";
      
      const LocaleSwitcher: FC = () => {
        const { pathname, search } = useLocation(); // 현재 URL 경로를 가져옵니다. 예: /fr/about?foo=bar
        const navigate = useNavigate();
      
        const { locale, availableLocales, setLocale } = useLocale({
          onLocaleChange: (locale) => {
            // 업데이트된 로케일로 URL을 구성합니다
            // 예: /es/about?foo=bar
            const pathWithLocale = getLocalizedUrl(`${pathname}${search}`, locale);
      
            // URL 경로를 업데이트합니다
            navigate(pathWithLocale);
          },
        });
      
        return (
          <div>
            <button popoverTarget="localePopover">{getLocaleName(locale)}</button>
            <div id="localePopover" popover="auto">
              {availableLocales.map((localeItem) => (
                <a
                  href={getLocalizedUrl(location.pathname, localeItem)}
                  hrefLang={localeItem}
                  aria-current={locale === localeItem ? "page" : undefined}
                  onClick={(e) => {
                    e.preventDefault();
                    setLocale(localeItem);
                  }}
                  key={localeItem}
                >
                  <span>
                    {/* 로케일 - 예: FR */}
                    {localeItem}
                  </span>
                  <span>
                    {/* 해당 로케일에서의 언어명 - 예: Français */}
                    {getLocaleName(localeItem, locale)}
                  </span>
                  <span dir={getHTMLTextDir(localeItem)} lang={localeItem}>
                    {/* 현재 로케일에서의 언어명 - 예: Francés (현재 로케일이 Locales.SPANISH일 때) */}
                    {getLocaleName(localeItem)}
                  </span>
                  <span dir="ltr" lang={Locales.ENGLISH}>
                    {/* 영어로 된 언어명 - 예: French */}
                    {getLocaleName(localeItem, Locales.ENGLISH)}
                  </span>
                </a>
              ))}
            </div>
          </div>
        );
      };
      

      문서 참고:

      아래는 추가 설명과 개선된 코드 예제가 포함된 업데이트된 9단계입니다:


    2. HTML 언어 및 방향 속성 전환

      선택사항

      애플리케이션이 여러 언어를 지원할 때, <html> 태그의 langdir 속성을 현재 로케일과 일치하도록 업데이트하는 것이 중요합니다. 이렇게 하면 다음을 보장합니다:

      • 접근성: 스크린 리더와 보조 기술은 올바른 lang 속성에 의존하여 콘텐츠를 정확하게 발음하고 해석합니다.
      • 텍스트 렌더링: dir (방향) 속성은 텍스트가 올바른 순서로 렌더링되도록 보장합니다(예: 영어의 경우 좌에서 우로, 아랍어 또는 히브리어의 경우 우에서 좌로). 이는 가독성에 필수적입니다.
      • SEO: 검색 엔진은 lang 속성을 사용하여 페이지의 언어를 결정하고 검색 결과에서 올바른 지역화된 콘텐츠를 제공하는 데 도움을 줍니다.

      로케일이 변경될 때 이러한 속성들을 동적으로 업데이트함으로써, 지원하는 모든 언어에서 사용자에게 일관되고 접근 가능한 경험을 보장합니다.

      Hook 구현하기

      HTML 속성을 관리하기 위한 커스텀 hook을 생성합니다. 이 hook은 로케일 변경을 감지하고 그에 따라 속성을 업데이트합니다:

      src/hooks/useI18nHTMLAttributes.tsx
      import { useEffect } from "react";
      import { useLocale } from "react-intlayer";
      import { getHTMLTextDir } from "intlayer";
      
      /**
       * 현재 로케일을 기반으로 HTML <html> 요소의 `lang` 및 `dir` 속성을 업데이트합니다.
       * - `lang`: 브라우저와 검색 엔진에 페이지의 언어를 알립니다.
       * - `dir`: 올바른 읽기 순서를 보장합니다 (예: 영어의 경우 'ltr', 아랍어의 경우 'rtl').
       *
       * 이 동적 업데이트는 올바른 텍스트 렌더링, 접근성 및 SEO에 필수적입니다.
       */
      export const useI18nHTMLAttributes = () => {
        const { locale } = useLocale();
      
        useEffect(() => {
          // 언어 속성을 현재 로케일로 업데이트합니다.
          document.documentElement.lang = locale;
      
          // 현재 로케일을 기반으로 텍스트 방향을 설정합니다.
          document.documentElement.dir = getHTMLTextDir(locale);
        }, [locale]);
      };
      

      훅 구현하기

      HTML 속성을 관리하는 커스텀 훅을 만듭니다. 이 훅은 로케일 변경을 감지하여 속성을 적절히 업데이트합니다:

      src/hooks/useI18nHTMLAttributes.tsx
      import { useEffect } from "react";
      import { useLocale } from "react-intlayer";
      import { getHTMLTextDir } from "intlayer";
      
      /**
       * 현재 로케일에 따라 HTML <html> 요소의 `lang` 및 `dir` 속성을 업데이트합니다.
       * - `lang`: 브라우저와 검색 엔진에 페이지의 언어를 알립니다.
       * - `dir`: 올바른 읽기 순서(예: 영어는 'ltr', 아랍어는 'rtl')를 보장합니다.
       *
       * 이 동적 업데이트는 올바른 텍스트 렌더링, 접근성 및 SEO에 필수적입니다.
       */
      export const useI18nHTMLAttributes = () => {
        const { locale } = useLocale();
      
        useEffect(() => {
          // 현재 로케일로 언어 속성을 업데이트합니다.
          document.documentElement.lang = locale;
      
          // 현재 로케일에 따라 텍스트 방향을 설정합니다.
          document.documentElement.dir = getHTMLTextDir(locale);
        }, [locale]);
      };
      

      이러한 변경 사항을 적용하면 애플리케이션은 다음을 수행합니다:

      • 언어 (lang) 속성이 현재 로캘을 올바르게 반영하는지 확인하세요. 이는 SEO와 브라우저 동작에 중요합니다.
      • 로캘에 따라 텍스트 방향 (dir)을 조정하여 다양한 읽기 순서를 가진 언어의 가독성과 사용성을 향상시키세요.
      • 접근성 있는 경험을 제공하세요. 보조 기술은 최적의 기능을 위해 이러한 속성에 의존합니다.
    3. 지역화된 링크 컴포넌트 만들기

      선택사항

      애플리케이션의 내비게이션이 현재 로케일을 준수하도록 하려면, 커스텀 Link 컴포넌트를 만들 수 있습니다. 이 컴포넌트는 내부 URL에 자동으로 현재 언어 접두사를 붙여줍니다. 예를 들어, 프랑스어 사용자가 "About" 페이지로 가는 링크를 클릭하면 /about 대신 /fr/about로 리디렉션됩니다.

      이 동작은 여러 가지 이유로 유용합니다:

      • SEO 및 사용자 경험: 지역화된 URL은 검색 엔진이 언어별 페이지를 올바르게 색인화하도록 돕고, 사용자가 선호하는 언어로 된 콘텐츠를 제공합니다.
      • 일관성: 애플리케이션 전반에 걸쳐 지역화된 링크를 사용함으로써 내비게이션이 현재 로케일 내에서 유지되어 예기치 않은 언어 전환을 방지합니다.
      • 유지보수성: 로컬라이제이션 로직을 단일 컴포넌트에 중앙 집중화하면 URL 관리를 단순화하여 애플리케이션이 성장함에 따라 코드베이스를 더 쉽게 유지보수하고 확장할 수 있습니다.

      아래는 TypeScript로 구현한 로컬라이즈된 Link 컴포넌트입니다:

      src/components/Link.tsx
      import { getLocalizedUrl } from "intlayer";
      import {
        forwardRef,
        type DetailedHTMLProps,
        type AnchorHTMLAttributes,
      } from "react";
      import { useLocale } from "react-intlayer";
      
      export interface LinkProps extends DetailedHTMLProps<
        AnchorHTMLAttributes<HTMLAnchorElement>,
        HTMLAnchorElement
      > {}
      
      /**
       * 주어진 URL이 외부 링크인지 확인하는 유틸리티 함수입니다.
       * URL이 http:// 또는 https://로 시작하면 외부 링크로 간주합니다.
       */
      export const checkIsExternalLink = (href?: string): boolean =>
        /^https?:\/\//.test(href ?? "");
      
      /**
       * 현재 로케일에 따라 href 속성을 조정하는 커스텀 Link 컴포넌트입니다.
       * 내부 링크의 경우 `getLocalizedUrl`을 사용하여 URL 앞에 로케일을 붙입니다 (예: /fr/about).
       * 이를 통해 내비게이션이 동일한 로케일 컨텍스트 내에서 이루어지도록 보장합니다.
       */
      export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
        ({ href, children, ...props }, ref) => {
          const { locale } = useLocale();
          const isExternalLink = checkIsExternalLink(href);
      
          // 링크가 내부 링크이고 유효한 href가 제공된 경우, 로케일이 적용된 URL을 가져옵니다.
          const hrefI18n =
            href && !isExternalLink ? getLocalizedUrl(href, locale) : href;
      
          return (
            <a href={hrefI18n} ref={ref} {...props}>
              {children}
            </a>
          );
        }
      );
      
      Link.displayName = "Link";
      

      작동 방식

      • 외부 링크 감지:
        헬퍼 함수 checkIsExternalLink는 지정된 URL이 외부 링크인지 여부를 판단합니다. 외부 링크는 현지화할 필요가 없으므로 변경되지 않은 상태로 유지됩니다.

      • 현재 로케일 가져오기:
        useLocale 훅은 현재 로케일(예: 프랑스어의 경우 fr)을 제공합니다.

      • URL 현지화:
        내부 링크(즉, 외부 링크가 아닌 링크)의 경우, getLocalizedUrl을 사용하여 현재 로케일로 URL 접두사를 자동으로 붙입니다. 즉, 사용자가 프랑스어 환경인 경우 /abouthref로 전달하면 /fr/about으로 변환됩니다.

      • 링크 반환:
        이 컴포넌트는 로컬라이즈된 URL이 적용된 <a> 요소를 반환하여 내비게이션이 로케일과 일치하도록 보장합니다.

      애플리케이션 전반에 이 Link 컴포넌트를 통합함으로써, 일관되고 언어를 인식하는 사용자 경험을 유지하는 동시에 개선된 SEO 및 사용성 이점을 누릴 수 있습니다.

    4. 컴포넌트 콘텐츠 추출

      선택사항

      기존 코드베이스가 있는 경우 수천 개의 파일을 변환하는 데 시간이 많이 걸릴 수 있습니다.

      이 프로세스를 용이하게 하기 위해 Intlayer는 컴포넌트를 변환하고 콘텐츠를 추출하기 위한 컴파일러 / 추출기를 제안합니다.

      설정하려면 intlayer.config.ts 파일에 compiler 섹션을 추가할 수 있습니다.

      intlayer.config.ts
      import { type IntlayerConfig } from "intlayer";
      
      const config: IntlayerConfig = {
        // ... 나머지 구성
        compiler: {
          /**
           * 컴파일러 활성화 여부를 나타냅니다.
           */
          enabled: true,
      
          /**
           * 출력 파일 경로를 정의합니다.
           */
          output: ({ fileName, extension }) => `./${fileName}${extension}`,
      
          /**
           * 변환 후 컴포넌트를 저장할지 여부를 나타냅니다. 그렇게 하면 컴파일러를 한 번만 실행하여 앱을 변환한 다음 제거할 수 있습니다.
           */
          saveComponents: false,
      
          /**
           * 사전 키 접두사
           */
          dictionaryKeyPrefix: "",
        },
      };
      
      export default config;
      

      컴포넌트를 변환하고 콘텐츠를 추출하기 위해 추출기를 실행합니다

      bash
      npx intlayer extract
      
      Since v9, the intlayerCompiler is included in the intlayer plugin. So you don't need to add it manually.

      vite.config.ts를 업데이트하여 intlayerCompiler 플러그인을 포함합니다.

      vite.config.ts
      import { defineConfig } from "vite";
      import { intlayer, intlayerCompiler } from "vite-intlayer";
      
      export default defineConfig({
        plugins: [
          intlayer(),
          intlayerCompiler(), // Adds the compiler plugin
        ],
      });
      
      bash
      npm run build # 또는 npm run dev
      

    (선택) 사이트맵과 robots.txt(빌드 시 생성)

    Intlayer는 generateSitemapgetMultilingualUrls로 크롤러용 다국어 sitemap.xmlrobots.txt를 만들어 public/에 자동으로 쓸 수 있습니다. 보통 Vite 실행 전에 작은 Node 스크립트를 돌립니다(예: npm predev / prebuild).

    사이트맵

    Intlayer 사이트맵 생성기는 로케일 설정을 반영하고 크롤러용 메타데이터를 포함합니다.

    생성된 사이트맵은 xhtml:link(hreflang)를 지원합니다. 단순 URL 나열이 아니라 각 페이지의 모든 언어 버전을 양방향으로 연결합니다(예: /about, /fr/about, /about?lang=fr - 라우팅 모드에 따름).

    Robots.txt

    getMultilingualUrlsDisallow가 민감 경로의 모든 현지화 변형에 적용되도록 하세요.

    1. 프로젝트 루트에 generate-seo.mjs 추가

    generate-seo.mjs
    import fs from "fs";
    import path from "path";
    import { fileURLToPath } from "url";
    import { generateSitemap, getMultilingualUrls } from "intlayer";
    
    const __dirname = path.dirname(fileURLToPath(import.meta.url));
    
    const SITE_URL = (process.env.SITE_URL || "http://localhost:5173").replace(
      /\/$/,
      ""
    );
    
    const pathList = [
      { path: "/", changefreq: "daily", priority: 1.0 },
      { path: "/about", changefreq: "monthly", priority: 0.7 },
    ];
    
    const sitemapXml = generateSitemap(pathList, { siteUrl: SITE_URL });
    fs.writeFileSync(path.join(__dirname, "public", "sitemap.xml"), sitemapXml);
    
    const getAllMultilingualUrls = (urls) =>
      urls.flatMap((url) => Object.values(getMultilingualUrls(url)));
    
    const disallowedPaths = getAllMultilingualUrls(["/admin", "/private"]);
    
    const robotsTxt = [
      "User-agent: *",
      "Allow: /",
      ...disallowedPaths.map((path) => `Disallow: ${path}`),
      "",
      `Sitemap: ${SITE_URL}/sitemap.xml`,
    ].join("\n");
    
    fs.writeFileSync(path.join(__dirname, "public", "robots.txt"), robotsTxt);
    
    console.log("SEO files generated successfully.");
    

    스크립트가 intlayer를 import하려면 패키지가 설치되어 있어야 합니다. 프로덕션에서는 환경 변수 SITE_URL을 설정하세요(CI 등).

    Node ESM에는 generate-seo.mjs 사용을 권장합니다. generate-seo.js를 쓰면 package.json"type": "module" 등으로 ESM을 켜세요.

    2. Vite 전에 스크립트 실행

    package.json
    {
      "scripts": {
        "dev": "vite",
        "prebuild": "node generate-seo.mjs",
        "build": "vite build",
        "preview": "vite preview"
      }
    }
    

    pnpm이나 yarn을 쓰면 명령을 맞게 바꾸세요. CI에서 호출해도 됩니다.

    TypeScript 설정

    Intlayer는 TypeScript의 이점을 활용하고 codebase를 더욱 강력하게 만들기 위해 module augmentation을 사용합니다.

    Autocompletion

    Translation error

    TypeScript 설정에 자동 생성된 타입이 포함되어 있는지 확인하세요.

    tsconfig.json
    {
      // ... 기존 TypeScript 설정
      "include": [
        // ... 기존 TypeScript 설정
        ".intlayer/**/*.ts", // 자동 생성된 타입 포함
      ],
    }
    

    Git 설정

    Intlayer에 의해 생성된 파일들을 무시할 것을 권장합니다. 이를 통해 해당 파일들이 Git 리포지토리에 커밋되는 것을 방지할 수 있습니다.

    이를 위해, .gitignore 파일에 다음 내용을 추가할 수 있습니다:

    .gitignore
    # Intlayer에서 생성된 파일 무시
    .intlayer
    

    VS Code 확장 프로그램

    Intlayer와 함께하는 개발 환경을 개선하기 위해 공식 Intlayer VS Code 확장 프로그램을 설치할 수 있습니다.

    VS Code 마켓플레이스에서 설치하기

    이 확장 프로그램은 다음을 제공합니다:

    • 번역 키에 대한 자동 완성(Autocompletion).
    • 누락된 번역에 대한 실시간 오류 감지.
    • 번역된 콘텐츠의 인라인 미리보기.
    • 번역을 쉽게 생성하고 업데이트할 수 있는 빠른 작업(Quick actions).

    확장 프로그램 사용법에 대한 자세한 내용은 Intlayer VS Code 확장 프로그램 문서를 참조하세요.


    더 나아가기

    더 나아가려면 비주얼 에디터를 구현하거나 CMS를 사용하여 콘텐츠를 외부화할 수 있습니다.