4

I am recently working with a legacy code in Vue.js with Typescript. The project has the vue-i18n library integrated to handle translations and they are managed with this.$t in all components of the project, also the translations are contained in directory translations/[en/es]/FileName.ts like:

//translations/en/Forms.ts

export default {
  Fields: {
    Name: "Name",
    LastName: "Last name",
    Direction: "Full direction",
    ZipCode: "Zip code",
    Phone: {
        Number: "Number",
        Prefix: "Prefix"
    }
  }
};

And translation usage is:

//pages/UserForm.vue

<div>
   <label> {{$t("Fields.Direction")}} </label>
   <input type="text" name="directionField" required />
</div>

However, within the <templates> there are many strings that don't use the library because the previous developers included these strings manually like:

<div v-if="hasError">
    Oops! There seem to be bugs
</div>

My question: Is there a method, library, plugin or script that can warn of all strings without translation?

mrcone
  • 51
  • 7

2 Answers2

0

Actually you have two options:

  1. Runtime check via validation methods
  2. Compile time check via typing functions

Runtime check

This one is pretty straightforward, just run all translations through some helper function, that throws error into the console, if translation is not present. But I think, vue-i18n already provides such functionality and you are here for option number 2.

Compile time check

You can make your translation function typesafe by providing types for incoming values.

Problem number one

Typing access to deeply nested structures via simple strings can be a really difficult task. If your goal is to type $t the way it will not accept any strings other than paths present in your translations. It can only be done using new TypeScript 4.1 version. To update to latest version, run npm i -D typescript.

I already asked similar question and got pretty far with this one. You can check out github repo of my properly-typed project. Types, handy for your task can be found here.

It can look something like this:

type TranslationsStructure = {
    Fields: {
        Name: string,
        LastName: string,
        Direction: string,
        ZipCode: string,
        Phone: {
            Number: string,
            Prefix: string
        }
    }
}

const typedTranslate = <
  T extends Record<string, unknown>,
  P extends Leaves<T, D>,
  D extends string = '.',
>(path: P): OutputType<T, P, D> => {
  return /* use `$t(path)` here to get translation */path as any;
};

// correct, because `Fields.Name` path exists in `TranslationsStructure`
typedTranslate<TranslationsStructure, 'Fields.Name'>('Fields.Name');

// errors, because `Foo.bar` path exists in `TranslationsStructure`
typedTranslate<TranslationsStructure, 'Foo.bar'>('Foo.bar');

Playground link

Maybe I will release it as NPM package soon, when I will have a time to do so. I will keep this thread updated.

Problem number two

Different languages can have different translations missing. In this case you will need a typecheck, based on a chosen language. So your typedTranslate function will need to have different types passed for different translations.

const en = {
    Fields: {
        Name: "Name",
        LastName: "Last name",
        Direction: "Full direction",
        ZipCode: "Zip code",
        Phone: {
            Number: "Number",
            Prefix: "Prefix"
        }
    }
};

const typedTranslate = <
  T extends Record<string, unknown>,
  P extends Leaves<T, D>,
  D extends string = '.',
>(path: P): OutputType<T, P, D> => {
  return /* use `$t(path)` here to get translation */path as any;
};

// correct, because `Fields.Name` path exists in `en` object
typedTranslate<typeof en, 'Fields.Name'>('Fields.Name')

// errors, because `Foo.bar` path exists in `en` object
typedTranslate<typeof en, 'Foo.bar'>('Foo.bar')

Playground link

Problem number three

As I see you have folder structures for each language, so you will need to aggregate it somehow into one object or type to use typedTranslate function

Temoncher
  • 644
  • 5
  • 15
  • Sorry, I think there has been a misunderstanding. All the keys in the project have a translation. In the VueJS project there are elements (like a `div`) that have a string as content, but that content is not a `$t` function: it is a natural language phrase like "This is an error". So, I would like to know if exists any tool (as a crawler or similar) that will detect these strings. – mrcone Dec 03 '20 at 12:49
  • Hm, so you want some tool that will mark every `Ooops!`? – Temoncher Dec 03 '20 at 12:52
  • Yes. `Ooops` or any string that isn't translated. – mrcone Dec 03 '20 at 18:01
  • How do yo plan to distinct not translated strings? – Temoncher Dec 03 '20 at 18:26
  • That is my question. I have the problem of having a lot of untranslated strings scattered throughout the code. – mrcone Dec 04 '20 at 06:42
0

If you use VS Code, there is a really great plugin called "i18n-ally" that has a feature to detect hard-coded strings.

It's an action you can find in the command palette. (At this time is is marked as experimental, but I've had some success with it)

leech
  • 8,293
  • 7
  • 62
  • 78