i18next / i18next-scanner

Scan your code, extract translation keys/values, and merge them into i18n resource files.
http://i18next.github.io/i18next-scanner
MIT License
567 stars 128 forks source link

How to scan Vue i18next strings #172

Open jonalxh opened 4 years ago

jonalxh commented 4 years ago

Hi, I'm trying to activate scanner in Vue files using Vue i18next but I've not been able to achieve it.

Translations with Vue are treated like this:

Config:

module.exports = {
    input: [
        'frontend/templates/*.{htm,html,js,jsx}',
        'assets/components/*.{htm,html,js,jsx,vue}',
        // Use ! to filter out files or directories
        '!app/**/*.spec.{js,jsx}',
        '!app/i18n/**',
        '!**/node_modules/**',
    ],
    output: './',
    options: {
        debug: true,
        func: {
            list: ['i18next.t', 'i18n.t', 'this.$t', '$t'],
            extensions: ['.js', '.jsx', '.vue']
        },
        trans: {
            component: 'Trans',
            i18nKey: 'i18nKey',
            defaultsKey: 'defaults',
            extensions: ['.vue','.js', '.jsx'],
            fallbackKey: function(ns, value) {
                return value;
            },
            acorn: {
                ecmaVersion: 10, // defaults to 10
                sourceType: 'module', // defaults to 'module'
                // Check out https://github.com/acornjs/acorn/tree/master/acorn#interface for additional options
            }
        },
        lngs: ['en','es'],
        ns: [
            'locale'
        ],
        defaultLng: 'en',
        defaultNs: 'locale',
        defaultValue: '__STRING_NOT_TRANSLATED__',
        resource: {
            loadPath: 'assets/locales/{{lng}}/{{ns}}.json',
            savePath: 'assets/locales/{{lng}}/{{ns}}.json',
            jsonIndent: 4,
            lineEnding: '\n'
        },
        nsSeparator: false, // namespace separator
        keySeparator: false, // key separator
        interpolation: {
            prefix: '{{',
            suffix: '}}'
        }
    },
    transform: function customTransform(file, enc, done) {
        "use strict";
        const parser = this.parser;
        const content = fs.readFileSync(file.path, enc);
        let count = 0;

        parser.parseFuncFromString(content, { list: ['i18next._', 'i18next.__', '$t', 'this.$t'] }, (key, options) => {
            parser.set(key, Object.assign({}, options, {
                nsSeparator: false,
                keySeparator: false
            }));
            ++count;
        });

        if (count > 0) {
            console.log(`i18next-scanner: count=${chalk.cyan(count)}, file=${chalk.yellow(JSON.stringify(file.relative))}`);
        }

        done();
    }
};

Thanks a lot for your help.

gornyyvladimir commented 4 years ago

Hello! Try this config, I think you don't need trans and transform options.

module.exports = {
  input: [
    'frontend/templates/*.{htm,html,js,jsx}',
    'assets/components/*.{htm,html,js,jsx,vue}',
    // Use ! to filter out files or directories
    '!app/**/*.spec.{js,jsx}',
    '!app/i18n/**',
    '!**/node_modules/**',
  ],
  output: './',
  options: {
    debug: true,
    func: {
      list: ['$t'],
      extensions: ['.js', '.jsx', '.vue', '.html', '.htm'],
    },
    trans: {
      component: 'Trans',
      extensions: [],
    },
    lngs: ['en', 'es'],
    ns: ['locale'],
    defaultLng: 'en',
    defaultNs: 'locale',
    defaultValue: '__STRING_NOT_TRANSLATED__',
    resource: {
      loadPath: 'assets/locales/{{lng}}/{{ns}}.json',
      savePath: 'assets/locales/{{lng}}/{{ns}}.json',
      jsonIndent: 4,
      lineEnding: '\n',
    },
    nsSeparator: false, // namespace separator
    keySeparator: false, // key separator
    interpolation: {
      prefix: '{{',
      suffix: '}}',
    },
  },
};

If it shows errors, please send it to us.

aeusse commented 4 years ago

I think the element '$t' in the func list should be double escaped. It worked for me:

func: {
  list: ['\\$t'],
  extensions: ['.js', '.jsx', '.vue', '.html', '.htm'],
},
jonalxh commented 4 years ago

Thanks Mr. @aeusse . It worked.

amanpatel commented 3 years ago

Would love it if the scanner supported extracting the namespace (if any) from the component part. I'm using vue-i18next (panter). And I do have some components that specify a default namespace so I don't have to do it over and over again in the template.


  i18nOptions: {
    defaultNS: 'network',
    //keyPrefix: '' use this if all the keys in this component
  },
...```

(also keyPrefix)
FVolral commented 4 months ago

I'm having these error messages when I try to scan a Vue 3 project migrated from Vue 2:

i18next-scanner: Unable to parse Trans component from "/Users/xxx/src/app/App.vue"
    SyntaxError: Unexpected token (8:9)

I've this error message for every Vue file of my project.

Here is my configuration :


const fs = require('fs')
const chalk = require('chalk')

module.exports = {
  options: {
    debug: true,
    func: {
      list: ['\\$t'],
      extensions: ['.js', '.vue']
    },
    trans: {
      extensions: ['.js', '.vue'],
      fallbackKey: (ns, value) => {
        return value
      }
    },
    lngs: ['de'],
    ns: ['translation'],
    defaultNs: 'translation',
    defaultValue: '',
    resource: {
      loadPath: 'src/i18n/{lng}/{ns}.json',
      savePath: 'src/i18n/{lng}/{ns}.json'
    },
    nsSeparator: false, // namespace separator
    keySeparator: false, // key separator

    interpolation: {
      prefix: '{',
      suffix: '}'
    }
  },
  transform: function customTransform (file, enc, done) {
    'use strict'
    const parser = this.parser
    const content = fs.readFileSync(file.path, enc)
    let count = 0

    parser.parseFuncFromString(content, { list: ['i18next._', 'i18next.__'] }, (key, options) => {
      parser.set(key, Object.assign({}, options, {
        nsSeparator: false,
        keySeparator: false
      }))
      ++count
    })

    if (count > 0) {
      console.log(`i18next-scanner: count=${chalk.cyan(count)}, file=${chalk.yellow(JSON.stringify(file.relative))}`)
    }

    done()
  }
}