Repository: xiCO2k/laravel-vue-i18n (ts)

Issue:
How can I pass a default value for the case of a non-existent or empty-string translation?
### Example

In every non-English language, I have a translation for the `warningMessage` variable. In the example, I copied the German file. The text in English is: _Attention! The original language of the page is English. You are currently browsing a page translated into German by the community. If you encounter any errors, please let us know!_

Naturally, I don't want to display it in English, so in the English file, I declare an empty string (to avoid discrepancies between the two files).

**de.json**
```json
{
  "warningMessage": "Achtung! Die Originalsprache der Seite ist Englisch. Sie durchsuchen gerade eine von der Gemeinschaft ins Deutsche übersetzte Seite. Wenn Sie Fehler bemerken, lassen Sie es uns bitte wissen!",
}
```

**en.json**
```json
{
  "warningMessage": "",
}
```

### Problem

However, **when I invoke the `trans('warningMessage')` function in English, it returns `warningMessage` instead of an empty string**. How can I provide the function with a default value for the case of an empty string or undeclared variable?

### Solution?

I temporarily added a space to the text. However, in this case, the length of the text is not 0 but 1, which is illogical for an empty string. Is there another solution? I would like to instruct the `trans` function to output nothing in the case of a 0-length string value in this situation.

**en.json**
```json
{
  "warningMessage": " ", // space
}
```

### Request

I think it would be perfectly fine to leave the `trans` function as it is and create another function, perhaps named `nullableTrans` or any other name, whose purpose is to avoid outputting the key as a result when the key does not exist or its value is of zero length.

While displaying the key is very useful, there are a few cases across multiple projects where I want to avoid it without having to modify the `trans` function everywhere afterward.

**de.json**
```json
{
  "warningMessage": "Achtung! ...",
}
```

```js
trans("warningMessage") // result: "Achtung! ..."
nullableTrans("warningMessage") // result: "Achtung! ..."
```

**en.json**
```json
{
  "warningMessage": "",
}
```

```js
trans("warningMessage") // result: "warningMessage"
nullableTrans("warningMessage") // result: ""
```

**cz.json**
```json
{
  "anotherKey": "...",
  // warningMessage not declared
}
```

```js
trans("warningMessage") // result: "warningMessage"
nullableTrans("warningMessage") // result: ""
```

Pull request:
fix: Not handling empty string translations.
Fixes #153

Patch:
diff --git a/src/index.ts b/src/index.ts
index 4c70d1a..25af773 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,4 @@
-import {reactive, Plugin, computed, ComputedRef, watchEffect} from 'vue'
+import { reactive, Plugin, computed, ComputedRef, watchEffect } from 'vue'
 import { OptionsInterface } from './interfaces/options'
 import { PluginOptionsInterface } from './interfaces/plugin-options'
 import { LanguageInterface } from './interfaces/language'
@@ -349,13 +349,13 @@ export class I18n {
     }
 
     for (const [key, value] of Object.entries(this.fallbackMessages)) {
-      if (!this.activeMessages[key] || this.activeMessages[key] === key) {
+      if (!this.isValid(messages[key]) || this.activeMessages[key] === key) {
         this.activeMessages[key] = value
       }
     }
 
     for (const [key] of Object.entries(this.activeMessages)) {
-      if (!messages[key] && !this.fallbackMessages[key]) {
+      if (!this.isValid(messages[key]) && !this.isValid(this.fallbackMessages[key])) {
         this.activeMessages[key] = null
       }
     }
@@ -392,7 +392,13 @@ export class I18n {
    */
   wTrans(key: string, replacements: ReplacementsInterface = {}): ComputedRef<string> {
     watchEffect(() => {
-      this.activeMessages[key] = this.findTranslation(key) || this.findTranslation(key.replace(/\//g, '.')) || key
+      let value = this.findTranslation(key)
+
+      if (!this.isValid(value)) {
+        value = this.findTranslation(key.replace(/\//g, '.'))
+      }
+
+      this.activeMessages[key] = this.isValid(value) ? value : key
     })
 
     return computed(() => this.makeReplacements(this.activeMessages[key], replacements))
@@ -420,7 +426,7 @@ export class I18n {
    * Find translation in memory.
    */
   findTranslation(key) {
-    if (this.activeMessages[key]) {
+    if (this.isValid(this.activeMessages[key])) {
       return this.activeMessages[key]
     }
 
@@ -457,6 +463,13 @@ export class I18n {
     return message
   }
 
+  /**
+   * Checks if the message provided is valid.
+   */
+  isValid(message: string | null | undefined): boolean {
+    return message !== undefined && message !== null
+  }
+
   /**
    * Resets all the data stored in memory.
    */


Test patch:
diff --git a/test/fixtures/lang/pt.json b/test/fixtures/lang/pt.json
index 0dcbd72..dc78b33 100644
--- a/test/fixtures/lang/pt.json
+++ b/test/fixtures/lang/pt.json
@@ -6,5 +6,6 @@
     "foo.bar": "baz",
     "Start/end": "Início/Fim",
     "Get started.": "Comece.",
-    "<div>Welcome</div>": "<div>Bem-vindo</div>"
+    "<div>Welcome</div>": "<div>Bem-vindo</div>",
+    "Empty string": ""
 }
diff --git a/test/translate.test.ts b/test/translate.test.ts
index b7a649d..3265f42 100644
--- a/test/translate.test.ts
+++ b/test/translate.test.ts
@@ -17,6 +17,12 @@ it('translates with "trans" helper', async () => {
   expect(trans('Welcome!')).toBe('Bem-vindo!');
 })
 
+it('handles empty translations', async () => {
+  await global.mountPlugin();
+
+  expect(trans('Empty string')).toBe('');
+})
+
 it('returns the same message if there is no resolve method provided', async () => {
   const wrapper = mount({ template: `<h1>{{ $t('Welcome!') }}</h1>` }, {
     global: {
@@ -256,4 +262,4 @@ it('checks if watching wTrans works if key does not exist', async () => {
   await loadLanguageAsync('en');
 
   expect(translated.value).toBe('Not existing translation');
-})
\ No newline at end of file
+})