Author:
    Creation:2025-05-20Last update:2026-09-27

    CI/CD рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдореЗрдВ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдЕрдиреБрд╡рд╛рдж рдЙрддреНрдкрдиреНрди рдХрд░реЗрдВ

    Intlayer рдЖрдкрдХреЗ рд╕рд╛рдордЧреНрд░реА рдШреЛрд╖рдгрд╛ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдиреБрд╡рд╛рджреЛрдВ рдХрд╛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдЙрддреНрдкрд╛рджрди рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЖрдкрдХреЗ рдХрд╛рд░реНрдпрдкреНрд░рд╡рд╛рд╣ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЗрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рдХрдИ рддрд░реАрдХреЗ рд╣реИрдВред

    рд╡рд┐рд╖рдп рд╕реВрдЪреА

    CMS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛

    Intlayer рдХреЗ рд╕рд╛рде, рдЖрдк рдПрдХ рдРрд╕рд╛ рдХрд╛рд░реНрдпрдкреНрд░рд╡рд╛рд╣ рдЕрдкрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд╣рд╛рдБ рдХреЗрд╡рд▓ рдПрдХ рд╣реА рд╕реНрдерд╛рдиреАрдп рднрд╛рд╖рд╛ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рдШреЛрд╖рд┐рдд рдХреА рдЬрд╛рддреА рд╣реИ, рдЬрдмрдХрд┐ рд╕рднреА рдЕрдиреБрд╡рд╛рдж CMS рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рджреВрд░рд╕реНрде рд░реВрдк рд╕реЗ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдпрд╣ рд╕рд╛рдордЧреНрд░реА рдФрд░ рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рдХреЛрдбрдмреЗрд╕ рд╕реЗ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрд▓рдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдЬрд┐рд╕рд╕реЗ рд╕рд╛рдордЧреНрд░реА рд╕рдВрдкрд╛рджрдХреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рд▓рдЪреАрд▓рд╛рдкрди рдорд┐рд▓рддрд╛ рд╣реИ рдФрд░ рд╣реЙрдЯ рдХрдВрдЯреЗрдВрдЯ рд░реАрд▓реЛрдбрд┐рдВрдЧ рд╕рдХреНрд╖рдо рд╣реЛрддреА рд╣реИ (рдкрд░рд┐рд╡рд░реНрддрди рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдкреБрдирдГ рдирд┐рд░реНрдорд╛рдг рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрддреА)ред

    рдЙрджрд╛рд╣рд░рдг рд╡рд┐рдиреНрдпрд╛рд╕

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    
    const config: IntlayerConfig = {
      internationalization: {
        locales: [Locales.ENGLISH, Locales.SPANISH, Locales.FRENCH],
        requiredLocales: [Locales.ENGLISH], // рд╡реИрдХрд▓реНрдкрд┐рдХ рд╕реНрдерд╛рдиреАрдп рднрд╛рд╖рд╛рдПрдБ рджреВрд░рд╕реНрде рд░реВрдк рд╕реЗ рдкреНрд░рдмрдВрдзрд┐рдд рдХреА рдЬрд╛рдПрдВрдЧреА
        defaultLocale: Locales.ENGLISH,
      },
      editor: {
        dictionaryPriorityStrategy: "distant_first", // рджреВрд░рд╕реНрде рд╕рд╛рдордЧреНрд░реА рдХреЛ рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рджреА рдЬрд╛рддреА рд╣реИ
    
        applicationURL: process.env.APPLICATION_URL, // CMS рджреНрд╡рд╛рд░рд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдиреЗ рд╡рд╛рд▓рд╛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди URL
    
        clientId: process.env.INTLAYER_CLIENT_ID, // CMS рдкреНрд░рдорд╛рдгрдкрддреНрд░
        clientSecret: process.env.INTLAYER_CLIENT_SECRET,
      },
      ai: {
        applicationContext: "рдпрд╣ рдПрдХ рдкрд░реАрдХреНрд╖рдг рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╣реИ", // рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЕрдиреБрд╡рд╛рдж рд╕реБрд╕рдВрдЧрдд рд░реВрдк рд╕реЗ рдЙрддреНрдкрдиреНрди рд╣реЛрдВ
      },
    };
    
    export default config;
    

    CMS рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рджреЗрдЦреЗрдВред

    Husky рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛

    рдЖрдк рдЕрдкрдиреЗ рд╕реНрдерд╛рдиреАрдп Git рд╡рд░реНрдХрдлрд╝реНрд▓реЛ рдореЗрдВ рдЕрдиреБрд╡рд╛рдж рдирд┐рд░реНрдорд╛рдг рдХреЛ Husky рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХреАрдХреГрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

    рдЙрджрд╛рд╣рд░рдг рд╡рд┐рдиреНрдпрд╛рд╕

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    
    const config: IntlayerConfig = {
      internationalization: {
        locales: [Locales.ENGLISH, Locales.SPANISH, Locales.FRENCH],
        requiredLocales: [Locales.ENGLISH], // рд╡реИрдХрд▓реНрдкрд┐рдХ рд▓реЛрдХрд▓ рджреВрд░рд╕реНрде рд░реВрдк рд╕реЗ рд╕рдВрднрд╛рд▓реЗ рдЬрд╛рддреЗ рд╣реИрдВ
        defaultLocale: Locales.ENGLISH,
      },
      editor: {
        clientId: process.env.INTLAYER_CLIENT_ID,
        clientSecret: process.env.INTLAYER_CLIENT_SECRET,
      },
      ai: {
        provider: "openai",
        apiKey: process.env.OPENAI_API_KEY, // рдЕрдкрдирд╛ рд╕реНрд╡рдпрдВ рдХрд╛ API рдХреБрдВрдЬреА рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
    
        applicationContext: "рдпрд╣ рдПрдХ рдкрд░реАрдХреНрд╖рдг рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╣реИ", // рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдЕрдиреБрд╡рд╛рдж рд╕реБрд╕рдВрдЧрдд рд░реВрдк рд╕реЗ рдЙрддреНрдкрдиреНрди рд╣реЛрдВ
      },
    };
    
    export default config;
    
    .husky/pre-push
    npx intlayer build                          # рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рд╢рдмреНрджрдХреЛрд╢ рдЕрджреНрдпрддрд┐рдд рд╣реИрдВ
    npx intlayer fill --unpushed --mode fill    # рдХреЗрд╡рд▓ рдЧрд╛рдпрдм рд╕рд╛рдордЧреНрд░реА рднрд░реЗрдВ, рдореМрдЬреВрджрд╛ рдХреЛ рдЕрдкрдбреЗрдЯ рдирд╣реАрдВ рдХрд░рддрд╛
    
    Intlayer CLI рдХрдорд╛рдВрдб рдФрд░ рдЙрдирдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд▓рд┐рдП, CLI рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рджреЗрдЦреЗрдВред
    рдпрджрд┐ рдЖрдкрдХреЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдХрдИ рдРрдкреНрд╕ рдЕрд▓рдЧ-рдЕрд▓рдЧ intlayer рдЗрдВрд╕реНрдЯреЗрдВрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рдЖрдк --base-dir рддрд░реНрдХ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
    .husky/pre-push
    # рдРрдк 1
    npx intlayer build --base-dir ./app1
    npx intlayer fill --base-dir ./app1 --unpushed --mode fill
    
    # рдРрдк 2
    npx intlayer build --base-dir ./app2
    npx intlayer fill --base-dir ./app2 --unpushed --mode fill
    

    GitHub Actions рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛

    Intlayer рдПрдХ CLI рдХрдорд╛рдВрдб рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ рдЬреЛ рд╢рдмреНрджрдХреЛрд╢ рд╕рд╛рдордЧреНрд░реА рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рднрд░рдиреЗ рдФрд░ рд╕рдореАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИред рдЗрд╕реЗ GitHub Actions рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЖрдкрдХреЗ CI/CD рд╡рд░реНрдХрдлрд╝реНрд▓реЛ рдореЗрдВ рдПрдХреАрдХреГрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

    .github/workflows/intlayer-translate.yml
    name: Intlayer рдСрдЯреЛ-рдлрд┐рд▓
    # рдЗрд╕ рд╡рд░реНрдХрдлрд╝реНрд▓реЛ рдХреЗ рд▓рд┐рдП рдЯреНрд░рд┐рдЧрд░ рд╢рд░реНрддреЗрдВ
    on:
      pull_request:
        branches:
          - "main"
    
    permissions:
      contents: write
      pull-requests: write
    
    concurrency:
      group: "autofill-${{ github.ref }}"
      cancel-in-progress: true
    
    jobs:
      autofill:
        runs-on: ubuntu-latest
        env:
          # OpenAI
          AI_PROVIDER: openai
          AI_MODEL: gpt-5.6-terra
          AI_API_KEY: ${{ secrets.AI_API_KEY }}
    
        steps:
          # рдЪрд░рдг 1: рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдирд╡реАрдирддрдо рдХреЛрдб рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ
          - name: тмЗя╕П рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдЪреЗрдХрдЖрдЙрдЯ рдХрд░реЗрдВ
            uses: actions/checkout@v4
            with:
              persist-credentials: true # PRs рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХреНрд░реЗрдбреЗрдВрд╢рд┐рдпрд▓реНрд╕ рд░рдЦреЗрдВ
              fetch-depth: 0 # рдбрд┐рдлрд╝ рдПрдирд╛рд▓рд┐рд╕рд┐рд╕ рдХреЗ рд▓рд┐рдП рдкреВрд░реА рдЧрд┐рдЯ рд╣рд┐рд╕реНрдЯреНрд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ
    
          # рдЪрд░рдг 2: Node.js рдкрд░реНрдпрд╛рд╡рд░рдг рд╕реЗрдЯ рдХрд░реЗрдВ
          - name: ЁЯЯв Node.js рд╕реЗрдЯ рдХрд░реЗрдВ
            uses: actions/setup-node@v4
            with:
              node-version: 20 # рд╕реНрдерд┐рд░рддрд╛ рдХреЗ рд▓рд┐рдП Node.js 20 LTS рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
    
          # рдЪрд░рдг 3: рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдирд┐рд░реНрднрд░рддрд╛рдПрдБ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░реЗрдВ
          - name: ЁЯУж рдирд┐рд░реНрднрд░рддрд╛рдПрдБ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░реЗрдВ
            run: npm install
    
          # рдЪрд░рдг 4: рдЕрдиреБрд╡рд╛рдж рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдП Intlayer CLI рдХреЛ рдЧреНрд▓реЛрдмрд▓реА рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░реЗрдВ
          - name: ЁЯУж Intlayer рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░реЗрдВ
            run: npm install -g intlayer-cli
    
          # рдЪрд░рдг 5: рдЕрдиреБрд╡рд╛рдж рдлрд╝рд╛рдЗрд▓реЗрдВ рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП Intlayer рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрдирд╛рдПрдВ
          - name: тЪЩя╕П Intlayer рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдмрдирд╛рдПрдВ
            run: npx intlayer build
    
          # рдЪрд░рдг 6: AI рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЧрд╛рдпрдм рдЕрдиреБрд╡рд╛рдж рднрд░реЗрдВ
          - name: ЁЯдЦ рдЧрд╛рдпрдм рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рднрд░реЗрдВ
            run: npx intlayer fill --git-diff --mode fill --provider $AI_PROVIDER --model $AI_MODEL --api-key $AI_API_KEY
    
          # рдЪрд░рдг 7: рдЬрд╛рдВрдЪреЗрдВ рдХрд┐ рдХреНрдпрд╛ рдХреЛрдИ рдкрд░рд┐рд╡рд░реНрддрди рд╣реИрдВ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдХрдорд┐рдЯ рдХрд░реЗрдВ
          - name: я┐╜ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдЬрд╛рдВрдЪ рдХрд░реЗрдВ
            id: check-changes
            run: |
              if [ -n "$(git status --porcelain)" ]; then
                echo "has-changes=true" >> $GITHUB_OUTPUT
              else
                echo "has-changes=false" >> $GITHUB_OUTPUT
              fi
    
          # рдЪрд░рдг 8: рдпрджрд┐ рдХреЛрдИ рдкрд░рд┐рд╡рд░реНрддрди рд╣реИрдВ рддреЛ рдЙрдиреНрд╣реЗрдВ рдХрдорд┐рдЯ рдФрд░ рдкреБрд╢ рдХрд░реЗрдВ
          - name: ЁЯУд рдкрд░рд┐рд╡рд░реНрддрди рдХрдорд┐рдЯ рдФрд░ рдкреБрд╢ рдХрд░реЗрдВ
            if: steps.check-changes.outputs.has-changes == 'true'
            run: |
              git config --local user.email "action@github.com"
              git config --local user.name "GitHub Action"
              git add .
              git commit -m "chore: рдЧрд╛рдпрдм рдЕрдиреБрд╡рд╛рджреЛрдВ рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рднрд░реЗрдВ [skip ci]"
              git push origin HEAD:${{ github.head_ref }}
    

    рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ рд╕реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, GitHub тЖТ Settings тЖТ Secrets and variables тЖТ Actions рдкрд░ рдЬрд╛рдПрдВ рдФрд░ рд╕реАрдХреНрд░реЗрдЯ рдЬреЛрдбрд╝реЗрдВред

    Husky рдХреЗ рд╕рдорд╛рди, рдореЛрдиреЛрд░рд┐рдкреЛ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЖрдк рдкреНрд░рддреНрдпреЗрдХ рдРрдк рдХреЛ рдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП --base-dir рддрд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
    рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, --git-diff рддрд░реНрдХ рдЙрди рд╢рдмреНрджрдХреЛрд╢реЛрдВ рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рддрд╛ рд╣реИ рдЬрд┐рдирдореЗрдВ рдмреЗрд╕ (рдбрд┐рдлрд╝реЙрд▓реНрдЯ origin/main) рд╕реЗ рд╡рд░реНрддрдорд╛рди рд╢рд╛рдЦрд╛ (рдбрд┐рдлрд╝реЙрд▓реНрдЯ: HEAD) рддрдХ рдХреЗ рдкрд░рд┐рд╡рд░реНрддрди рд╢рд╛рдорд┐рд▓ рд╣реЛрддреЗ рд╣реИрдВред
    Intlayer CLI рдХрдорд╛рдВрдб рдФрд░ рдЙрдирдХреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд▓рд┐рдП, CLI рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рджреЗрдЦреЗрдВред