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

Issue:
Language files are not Reading Recursive
I used this plugin but i'm running into a issue.

My lang folder structure is as follow:
```
Lang
| en
  | pages
  | - admin
  | - - dashboard.php
  | pagination.php
  | validation.php
| nl
  | pages
  | - admin
  | - - dashboard.php
  | pagination.php
  | validation.php
| php_en.json
| php_nl.json
  ```
  But if i read the json files, i only see the translations from the files of the root dir of a languages and not the sub folder translations.
  
  Or is there any fix for it?
  
  App.js:
  ```js
import './bootstrap';
import '../css/app.css';

import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/inertia-vue3';
import { InertiaProgress } from '@inertiajs/progress';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
import { i18nVue } from 'laravel-vue-i18n';

const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
    setup({ el, app, props, plugin }) {
        return createApp({ render: () => h(app, props) })
            .use(plugin)
            .use(ZiggyVue, Ziggy)
            .use(i18nVue, {
                resolve: async lang => {
                    const langs = import.meta.glob('../../lang/php_*.json');
                    return await langs[`../../lang/php_${lang}.json`]();
                }
            })
            .mount(el);
    },
});

InertiaProgress.init({ color: '#4B5563' });
```
Vite Config:
```js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import i18n from 'laravel-vue-i18n/vite';

export default defineConfig({
    plugins: [
        laravel({
            input: 'resources/js/app.js',
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),

        // https://github.com/xiCO2k/laravel-vue-i18n
        i18n(),
    ],
});
```
  
  
  Versions:
  Laravel 9.38
  PHP: 8.1.0
  Yarn: 1.22.19
  Vite: 3.0.0
  Vue: 3.2.41

Pull request description:
fix: Nested translations aren't translated
Fixes #84

Also adds `/` as a possible trans delimiter. The reason is type hinting in PHPStorm because that's the default way Laravel has made nested translations.

Patch:
diff --git a/src/index.ts b/src/index.ts
index 5eba1b0..b413be3 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -337,6 +337,8 @@ export class I18n {
    * Get the translation for the given key and watch for any changes.
    */
   wTrans(key: string, replacements: ReplacementsInterface = {}): ComputedRef<string> {
+    key = key.replace(/\//g, '.')
+
     if (!this.activeMessages[key]) {
       const hasChildItems = this.activeMessages[`${key}.0`] !== undefined
 
diff --git a/src/loader.ts b/src/loader.ts
index 3c6ec03..96f7a7b 100644
--- a/src/loader.ts
+++ b/src/loader.ts
@@ -35,32 +35,9 @@ export const parseAll = (folderPath: string): { name: string; path: string }[] =
 
   const data = []
   for (const folder of folders) {
-    const lang = {}
+    const langFolderPath = folderPath + path.sep + folder
 
-    fs.readdirSync(folderPath + path.sep + folder)
-      .sort()
-      .forEach((langFolderItem) => {
-        const langFolderPath = folderPath + path.sep + folder
-        const langFolderItemPath = langFolderPath + path.sep + langFolderItem
-
-        if (fs.statSync(langFolderItemPath).isDirectory()) {
-          // Lang sub folder
-          const subFolderFileKey = langFolderItem.replace(/\.\w+$/, '')
-          lang[subFolderFileKey] = {}
-
-          fs.readdirSync(langFolderItemPath)
-            .filter((file) => !fs.statSync(langFolderItemPath + path.sep + file).isDirectory())
-            .sort()
-            .forEach((file) => {
-              lang[subFolderFileKey][file.replace(/\.\w+$/, '')] = parse(
-                fs.readFileSync(langFolderItemPath + path.sep + file).toString()
-              )
-            })
-        } else {
-          // Lang file
-          lang[langFolderItem.replace(/\.\w+$/, '')] = parse(fs.readFileSync(langFolderItemPath).toString())
-        }
-      })
+    const lang = readThroughDir(langFolderPath)
 
     data.push({
       folder,
@@ -147,3 +124,22 @@ export const reset = (folderPath) => {
       fs.unlinkSync(folderPath + file)
     })
 }
+
+export const readThroughDir = (dir) => {
+  const data = {}
+
+  fs.readdirSync(dir)
+    .forEach((file) => {
+      const absoluteFile = dir + path.sep + file
+
+      if (fs.statSync(absoluteFile).isDirectory()) {
+        const subFolderFileKey = file.replace(/\.\w+$/, '')
+
+        data[subFolderFileKey] = readThroughDir(absoluteFile)
+      } else {
+        data[file.replace(/\.\w+$/, '')] = parse(fs.readFileSync(absoluteFile).toString())
+      }
+    })
+
+  return data
+}
\ No newline at end of file


Test patch:
diff --git a/test/fixtures/lang/en/nested/cars/car.php b/test/fixtures/lang/en/nested/cars/car.php
new file mode 100644
index 0000000..7e59b79
--- /dev/null
+++ b/test/fixtures/lang/en/nested/cars/car.php
@@ -0,0 +1,10 @@
+<?php
+
+return [
+    'is_electric' => 'Electric',
+    'foo' => [
+        'level1' => [
+            'level2' => 'barpt',
+        ]
+    ]
+];
\ No newline at end of file
diff --git a/test/fixtures/lang/pt/nested/cars/car.php b/test/fixtures/lang/pt/nested/cars/car.php
new file mode 100644
index 0000000..2dca6c1
--- /dev/null
+++ b/test/fixtures/lang/pt/nested/cars/car.php
@@ -0,0 +1,10 @@
+<?php
+
+return [
+    'is_electric' => 'É elétrico?',
+    'foo' => [
+        'level1' => [
+            'level2' => 'barpt',
+        ]
+    ]
+];
\ No newline at end of file
diff --git a/test/loader.test.ts b/test/loader.test.ts
index 755dd18..30c009e 100644
--- a/test/loader.test.ts
+++ b/test/loader.test.ts
@@ -30,6 +30,14 @@ it('includes .php lang file in subdirectory in .json', () => {
     expect(langEn['domain.car.foo.level1.level2']).toBe('barpt');
 });
 
+it('includes .php lang file in nested subdirectory in .json', () => {
+    const files = parseAll(__dirname + '/fixtures/lang/');
+    const langEn = JSON.parse(fs.readFileSync(files[0].path).toString())
+
+    expect(langEn['nested.cars.car.is_electric']).toBe('Electric');
+    expect(langEn['nested.cars.car.foo.level1.level2']).toBe('barpt');
+})
+
 it('transforms .php lang to .json', () => {
     const lang = parse(fs.readFileSync(__dirname + '/fixtures/lang/en/auth.php').toString());
 
diff --git a/test/translate.test.ts b/test/translate.test.ts
index 39a4a6b..883a807 100644
--- a/test/translate.test.ts
+++ b/test/translate.test.ts
@@ -191,3 +191,10 @@ it('translates a possible nested item, and if not exists check on the root level
   await global.mountPlugin(undefined, 'pt');
   expect(trans('foo.bar')).toBe('baz');
 });
+
+it('translates a nested file item while using "/" and "." at the same time as a delimiter', async () => {
+  await global.mountPlugin()
+
+  expect(trans('nested/cars/car.is_electric')).toBe('É elétrico?');
+  expect(trans('nested/cars/car.foo.level1.level2')).toBe('barpt');
+})
\ No newline at end of file