지식 정리 📝

GitHub Copilot을 활용한 사용하지 않는 번역 키 제거

엄성준 2025. 11. 13. 20:02
728x90

프로젝트 내 다국어(i18n)를 관리하다 보면, 기능이 변경되거나 삭제될 때마다 사용하지 않는 번역 키가 남게 됩니다.


이번에는 WiniLogis 프로젝트에서 점점 쌓여가던 불필요한 다국어 키를 정리한 과정을 공유하려고 합니다.


❗️ 문제 상황

WiniLogis에서는 Google Cloud Sheet를 기반으로 다국어를 관리하고 있습니다. 개발 환경에서는 스크립트를 통해 Sheet에 작성된 다국어 데이터를 public/locales/{언어}/translation.json 형태로 변환하여 저장합니다.

public/
 └─ locales/
     ├─ en/translation.json
     ├─ es/translation.json
     └─ ru/translation.json

 

그러나 프로젝트가 커지고 여러 기능이 추가 및 삭제되면서, 점점 사용되지 않는 번역 키들이 누적되기 시작했습니다. 그 결과, Google Sheet에는 실제로 사용되지 않는 다국어가 계속 남게 되었습니다.


🔍 문제 분석

i18n 시스템 자체에는 “이 키가 실제로 사용 중인지”를 자동으로 알려주는 기능이 없습니다. 즉, 개발자가 직접 프로젝트 코드를 모두 뒤져서 확인해야 하는데, 이는 현실적으로 많이 힘들 것 같습니다.

 

그래서 다음과 같은 접근으로 문제를 해결하기로 했습니다:

  1. translation.json 파일에서 모든 다국어 키 추출
  2. src 폴더 내 모든 코드 파일을 탐색하며 해당 키가 실제로 사용되는지 확인
  3. 사용되지 않는 키만 별도로 출력하여 정리

✅ 해결 방법

이 과정을 최적화하기 위해, GitHub Copilot의 도움을 받아 사용되지 않는 i18n 키를 찾아주는 스크립트를 작성했습니다.

// 스크립트: 사용되지 않는 i18n 키 찾기
import fs from 'fs';
import path from 'path';

const LOCALES_DIR = './public/locales/en/translation.json';

// JSON 파일 읽기
const translationData = JSON.parse(fs.readFileSync(LOCALES_DIR, 'utf8'));

// 모든 키 추출 (중첩된 키도 점(.)으로 연결)
const getAllKeys = (obj, prefix = '') => {
  let keys = [];

  for (const key in obj) {
    const fullKey = prefix ? `${prefix}.${key}` : key;

    if (typeof obj[key] === 'object' && obj[key] !== null) {
      keys = keys.concat(getAllKeys(obj[key], fullKey));
    } else {
      keys.push(fullKey);
    }
  }

  return keys;
};

// src 폴더 내 재귀적으로 특정 확장자 파일 모두 찾기 (node_modules 제외)
const getFilesRecursive = (dir, extensions) => {
  let results = [];

  const list = fs.readdirSync(dir, { withFileTypes: true });

  for (const file of list) {
    const fullPath = path.join(dir, file.name);

    if (file.isDirectory()) {
      if (file.name === 'node_modules') continue;
      results = results.concat(getFilesRecursive(fullPath, extensions));
    } else {
      if (extensions.includes(path.extname(file.name))) {
        results.push(fullPath);
      }
    }
  }

  return results;
};

// 프로젝트 파일에서 특정 키가 사용 중인지 확인
const checkKeyUsage = (keyToCheck) => {
  const files = getFilesRecursive('src', ['.ts', '.tsx', '.js', '.jsx']);

  for (const file of files) {
    try {
      const content = fs.readFileSync(file, 'utf8');

      // 다양한 패턴으로 키 사용 여부 체크
      const patterns = [
        `'${keyToCheck}'`,
        `"${keyToCheck}"`,
        `\`${keyToCheck}\``,
        `t('${keyToCheck}')`,
        `t("${keyToCheck}")`,
      ];

      if (patterns.some((pattern) => content.includes(pattern))) {
        return true; // 사용 중
      }
    } catch (error) {
      console.error(`Error reading file ${file}:`, error.message);
    }
  }

  return false; // 사용 안 함
};

// 메인 함수: 사용하지 않는 키 출력
const findUnusedKeys = () => {
  const allKeys = getAllKeys(translationData);
  const unusedKeys = [];

  for (const key of allKeys) {
    const isUsed = checkKeyUsage(key);

    if (!isUsed) {
      unusedKeys.push(key);
    }
  }

  console.log('Unused i18n Keys:', unusedKeys.length);
  unusedKeys.forEach((key) => console.log(key));
};

// 실행
findUnusedKeys();

 


💡 느낀 점

스크립트 실행 결과, 총 69개의 사용되지 않는 다국어 키를 발견했습니다.

 

이 키들은 Google Cloud Sheet에서도 동일하게 제거했으며, 이후 자동 동기화 스크립트를 다시 실행해 translation.json 파일이 정리된 상태로 유지되도록 했습니다.

 

GitHub Copilot 덕분에 반복적인 탐색 로직을 빠르게 작성할 수 있었고, 앞으로는 이 스크립트를 정기적으로 실행해 다국어 데이터를 항상 깨끗한 상태로 유지할 계획입니다.