npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

vuei18n-extractor

v2.4.0

Published

Automated translation key extractor for vue-i18n with composition API support

Readme

vuei18n-extractor

CI npm version License: MIT Node.js Version

🌍 Automated translation key extractor for vue-i18n with Composition API support

Extrator automatizado de chaves de tradução para vue-i18n, projetado para simplificar a internacionalização de aplicações Vue.js.

✨ Features

  • 🚀 Extração automática de chaves t() de arquivos Vue e JavaScript
  • 🌐 Suporte a múltiplos idiomas simultaneamente
  • 📦 Múltiplos formatos de saída (JS, JSON, TypeScript)
  • 🔄 Preserva traduções existentes
  • 📝 Agrupa chaves por arquivo de origem
  • ⚙️ Configuração flexível (JS ou JSON)
  • 🎯 Zero dependências de runtime
  • ✨ NOVO: Suporte a interpolação de variáveis {name}
  • ✨ NOVO: Suporte a pluralização (ICU MessageFormat) {count, plural, ...}
  • ✨ NOVO: Suporte a formatação de datas {date, date, short}
  • ✨ NOVO: Arquivo index.js/ts gerado automaticamente para fácil import
  • ✨ NOVO: Divisão inteligente em múltiplos arquivos (feature splitting)
  • 🔄 NOVO: Migração automática preservando traduções (resolve arquivos com [id], [slug])
  • 🔒 NOVO: Segurança robusta contra injection attacks

📦 Instalação

npm install -g vuei18n-extractor

Ou use diretamente com npx:

npx vuei18n-extractor

🚀 Uso Rápido

1. Crie o arquivo de configuração

Crie um arquivo i18nExtractor.js ou i18nExtractor.json na raiz do projeto:

1. Crie o arquivo de configuração

Crie um arquivo i18nExtractor.js ou i18nExtractor.json na raiz do projeto:

Opção 1: JavaScript (recomendado)

// i18nExtractor.js
module.exports = {
  header: "export default",      // ou "module.exports=" para CommonJS
  sourceLocale: "pt",            // idioma fonte
  locales: ["pt", "en", "es"],   // todos os idiomas
  format: "js",                  // formato de saída: "js", "json" ou "ts"
  catalogs: {
    outputFolder: "src/locales", // onde salvar os arquivos
    include: ["src/**/*.{vue,js,ts}"],  // arquivos para escanear
    exclude: ["src/locales/*"]   // arquivos para ignorar
  }
};

Opção 2: JSON

{
  "sourceLocale": "en",
  "locales": ["en", "fr", "de"],
  "format": "json",
  "catalogs": {
    "outputFolder": "locales",
    "include": ["src/**/*.vue"],
    "exclude": []
  }
}

2. Use t() no seu código

Tradução simples:

<script setup>
import { useI18n } from 'vue-i18n';

const { t } = useI18n();

const greeting = t("Hello World");
</script>

<template>
  <h1>{{ t("Welcome to my app") }}</h1>
</template>

Com interpolação de variáveis:

<script setup>
const welcome = t("Hello {name}, welcome back!");
const message = t("You have {count} new messages");
</script>

<template>
  <p>{{ t("Welcome, {username}!") }}</p>
</template>

Com pluralização (ICU MessageFormat):

<script setup>
// Pluralização automática baseada no count
const items = t("{count, plural, =0 {no items} one {# item} other {# items}}");
const notifications = t("{n, plural, zero {no notifications} one {# notification} other {# notifications}}");
</script>

<template>
  <span>{{ t("{count, plural, one {# message} other {# messages}}") }}</span>
</template>

Com formatação de data:

<script setup>
const today = t("Today is {date, date, long}");
const time = t("Current time: {now, time, short}");
</script>

Exemplo complexo:

<script setup>
const complex = t("Hello {name}, you have {count, plural, zero {no messages} one {# message} other {# messages}} from {date, date, short}");
</script>

3. Execute o extrator

npx vuei18n-extractor

4. Resultado

O extrator gera arquivos de tradução automaticamente com metadados úteis:

src/locales/pt.js (idioma fonte)

export default {
  /*
   src/Component.vue
  */
  // Variables: name
  "Hello {name}, welcome back!": "Hello {name}, welcome back!",
  
  // Uses pluralization
  "{count, plural, one {# item} other {# items}}": "{count, plural, one {# item} other {# items}}",
  
  // Uses date formatting
  "Today is {date, date, long}": "Today is {date, date, long}",
  
  "Welcome to my app": "Welcome to my app",
};

src/locales/en.js (outros idiomas - com metadados para facilitar tradução)

export default {
  /*
   src/Component.vue
  */
  // Variables: name
  "Hello {name}, welcome back!": "",
  
  // Uses pluralization
  "{count, plural, one {# item} other {# items}}": "",
  
  // Uses date formatting
  "Today is {date, date, long}": "",
  
  "Welcome to my app": "",
};

src/locales/index.js (✨ NOVO - gerado automaticamente!)

import pt from './pt.js';
import en from './en.js';

export const messages = {
  'pt': pt,
  'en': en
};

export default messages;

5. Configure Vue i18n

// src/i18n.ts
import { createI18n } from 'vue-i18n';
import pt from './locales/pt';
import en from './locales/en';

export default createI18n({
  locale: 'pt',
  fallbackLocale: 'en',
  messages: { pt, en },
});

Com splitting ativo, cada arquivo de locale (pt.js) importa automaticamente todos seus namespaces!

⚙️ Opções de Configuração

| Opção | Tipo | Obrigatório | Padrão | Descrição | |-------|------|-------------|--------|-----------| | sourceLocale | string | ✅ | - | Idioma fonte do projeto | | locales | string[] | ✅ | - | Lista de todos os idiomas suportados | | format | "js" \| "json" \| "ts" | ✅ | - | Formato dos arquivos de saída | | header | string | ❌ | "module.exports=" | Cabeçalho dos arquivos gerados | | catalogs.outputFolder | string | ✅ | - | Diretório para salvar arquivos | | catalogs.include | string[] | ✅ | - | Padrões glob de arquivos para escanear | | catalogs.exclude | string[] | ❌ | [] | Padrões glob de arquivos para ignorar | | splitting | object | ❌ | - | Configuração para dividir traduções em múltiplos arquivos |

📂 Dividindo Traduções em Múltiplos Arquivos

Para projetos grandes, você pode dividir automaticamente as traduções em múltiplos arquivos baseado na estrutura do projeto. Você continua escrevendo mensagens em linguagem natural, o splitting é transparente!

Estratégias Disponíveis

1. Flat (Padrão) - Todas traduções em um único arquivo

// Sem configuração de splitting

2. Directory - Baseado na estrutura de diretórios

{
  splitting: {
    strategy: "directory",
    maxDepth: 2
  }
}
// src/pages/auth/Login.vue → namespace: "pages.auth"
// Gera: pt.pages.auth.js, en.pages.auth.js

3. Feature - Baseado em pastas de features

{
  splitting: {
    strategy: "feature",
    featureFolders: ["features", "modules"]
  }
}
// src/features/auth/Login.vue → namespace: "auth"
// Gera: pt.auth.js, en.auth.js

4. Custom - Função personalizada

{
  splitting: {
    strategy: "custom",
    customNamespace: (filePath, baseDir) => {
      if (filePath.includes('/admin/')) return 'admin';
      if (filePath.includes('/public/')) return 'public';
      return 'common';
    }
  }
}

📚 Documentação completa sobre Splitting →

🔄 Migração Automática de Arquivos

Problema resolvido: Se você tinha arquivos com nomes inválidos (ex: pt-BR.pages.employees.[id].js) devido ao uso de rotas dinâmicas do Vue Router, não é mais necessário deletar e traduzir tudo novamente! 🎉

Como Funciona

O extrator detecta automaticamente arquivos com caracteres inválidos ([, ], (, ), {, }, <, >) e:

  1. Renomeia para o formato sanitizado
  2. Preserva todas as traduções existentes
  3. Mescla duplicados se necessário (novo tem prioridade)
  4. Funciona com JS, TS e JSON
  5. Zero configuração necessária

Exemplos de Migração

# Antes da migração (nomes inválidos)
src/locales/
  ├── pt-BR.pages.employees.[id].js
  ├── en.pages.products.[slug].ts
  └── es-ES.components.(group).items.[customId].json

# Depois da migração automática (nomes válidos)
src/locales/
  ├── pt-BR.pages.employees.id.js      ✅ Traduções preservadas
  ├── en.pages.products.slug.ts         ✅ Traduções preservadas
  └── es-ES.components.group.items.param.json  ✅ Traduções preservadas

Conversões Aplicadas

| Padrão Original | Convertido Para | Exemplo | |----------------|-----------------|---------| | [id] | id | pages.users.[id]pages.users.id | | [slug] | slug | posts.[slug]posts.slug | | [qualquercoisa] | param | items.[customId]items.param | | (grupo) | grupo | pages.(admin)pages.admin | | Múltiplos | Combinado | pages.[id].edit.[tab]pages.id.edit.param |

Mesclagem de Duplicados

Se você tiver ambos os arquivos (antigo e novo):

// pt-BR.pages.users.[id].js (arquivo antigo com traduções)
export default {
  "title": "Perfil do Usuário",
  "edit": "Editar",
  "shared": "Do arquivo antigo"
};

// pt-BR.pages.users.id.js (arquivo novo já existente)
export default {
  "name": "Nome",
  "shared": "Do arquivo novo"
};

// Resultado após migração (mescla inteligente)
export default {
  "title": "Perfil do Usuário",  // Do antigo
  "edit": "Editar",               // Do antigo
  "name": "Nome",                 // Do novo
  "shared": "Do arquivo novo"     // Novo tem prioridade
};

Quando Acontece

A migração é executada automaticamente antes de cada extração:

npx vuei18n-extractor

# Output:
# 📦 Migrated pt-BR.pages.employees.[id].js → pt-BR.pages.employees.id.js
# 📦 Migrated en.pages.products.[slug].ts → en.pages.products.slug.ts
# 🔀 Merged es.pages.items.[id].js → es.pages.items.id.js (duplicate resolved)
# ✓ Migrated 3 file(s) to sanitized names
#
# 📂 Scanning 45 file(s)...
# 🔑 Found 234 unique key(s)
# ...

Benefícios:

  • ✅ Sem perda de traduções
  • ✅ Sem trabalho manual
  • ✅ Funciona com qualquer quantidade de arquivos
  • ✅ Resolve conflitos automaticamente
  • ✅ Idempotente (pode executar múltiplas vezes sem problemas)

📚 Documentação completa sobre Splitting →

📖 Exemplos

Exemplo com TypeScript

// i18nExtractor.js
module.exports = {
  header: "export default",
  sourceLocale: "en",
  locales: ["en", "ja", "ko"],
  format: "ts",
  catalogs: {
    outputFolder: "src/i18n/locales",
    include: ["src/**/*.{vue,ts,tsx}"],
    exclude: ["src/**/*.spec.ts", "src/i18n/*"]
  }
};

Exemplo com JSON

// i18nExtractor.js
module.exports = {
  sourceLocale: "pt",
  locales: ["pt", "en"],
  format: "json",
  catalogs: {
    outputFolder: "public/locales",
    include: ["src/components/**/*.vue", "src/views/**/*.vue"],
    exclude: []
  }
};

🔍 Como Funciona

  1. Escaneamento: Busca todos os arquivos que correspondem aos padrões include
  2. Extração: Encontra todas as chamadas t("key") ou t('key') no código
  3. Agrupamento: Organiza chaves por arquivo de origem
  4. Geração: Cria/atualiza arquivos de locale preservando traduções existentes
  5. Limpeza: Remove chaves que não existem mais no código

⚠️ Limitações

❌ Não Suportado (ainda)

  • Chaves dinâmicas: t(variableName)
  • Chamadas com expressões: t("key" + suffix)

✅ Suportado

  • Strings literais: t("key")
  • Interpolação: t("Hello {name}")
  • Pluralização ICU: t("{count, plural, one {# item} other {# items}}")
  • Formatação de data: t("{date, date, short}")
  • Template literals: t(`Hello {name}`)
  • Múltiplas linhas (dentro de strings) ✅

🔒 Segurança

Esta biblioteca foi desenvolvida com segurança em mente:

  • Proteção contra Path Traversal: Todos os caminhos são validados
  • Proteção contra Code Injection: Strings são escapadas adequadamente
  • Validação de Configuração: Schema estrito com whitelist
  • Proteção contra ReDoS: Regex com repetição limitada
  • Sanitização de Variáveis: Apenas nomes válidos são aceitos
  • Validação de ICU MessageFormat: Sintaxe validada antes de processar

Exemplos de Proteção

// ❌ Path traversal bloqueado
{
  "catalogs": {
    "outputFolder": "../../../etc"  // ERRO: Path traversal detectado
  }
}

// ❌ Locale inválido bloqueado
{
  "locales": ["en; rm -rf /"]  // ERRO: Caracteres inválidos
}

// ❌ Chaves maliciosas são escapadas
t('test"; maliciousCode(); "')  // Escapado automaticamente

🛠️ Desenvolvimento

Pré-requisitos

  • Node.js >= 18.0.0
  • npm ou yarn

Setup do Projeto

# Clone o repositório
git clone https://github.com/abraaobuenotype/vuei18n-extractor.git
cd vuei18n-extractor

# Instale dependências
npm install

Scripts Disponíveis

# Executar testes
npm test

# Testes em modo watch
npm run test:watch

# Cobertura de testes
npm run test:coverage

# Verificar código (linting)
npm run lint

# Corrigir problemas de lint
npm run lint:fix

# Formatar código
npm run format

# Verificar formatação
npm run format:check

Rodando os Testes

npm test

15 testes unitários e de integração garantem a qualidade do código.

🤝 Contribuindo

Contribuições são bem-vindas! Sinta-se à vontade para:

  1. Fazer fork do projeto
  2. Criar uma branch para sua feature (git checkout -b feature/MinhaFeature)
  3. Commit suas mudanças (git commit -m 'Adiciona MinhaFeature')
  4. Push para a branch (git push origin feature/MinhaFeature)
  5. Abrir um Pull Request

Por favor, certifique-se de:

  • ✅ Adicionar testes para novas funcionalidades
  • ✅ Executar npm run lint e npm run format
  • ✅ Todos os testes passando (npm test)

📝 Changelog

Veja CHANGELOG.md para histórico de versões e mudanças.

📄 Licença

MIT © Abraao Bueno

💡 Inspiração

Inspirado na biblioteca lingui para React.

🙏 Agradecimentos

Obrigado a todos os contribuidores que ajudaram a melhorar este projeto!