Skip to content

Commit

Permalink
improve path access add i18n example
Browse files Browse the repository at this point in the history
  • Loading branch information
pikax committed Feb 22, 2020
1 parent f8515c3 commit 44b90d3
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 10 deletions.
4 changes: 4 additions & 0 deletions examples/vue-composable-example/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
<li>
<router-link to="/validation">Validation</router-link>
</li>

<li>
<router-link to="/i18n">I18n</router-link>
</li>
</ul>
<router-view></router-view>
</div>
Expand Down
132 changes: 132 additions & 0 deletions examples/vue-composable-example/src/components/I18n.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<template>
<div>
<div>
<select v-model="locale">
<option v-for="l in locales" :key="l" :value="l">{{
i18n.locales[l]
}}</option>
</select>
<div>
<label for="name">{{ i18n.input.name.label }}</label>
<input
name="name"
v-model="name"
:placeholder="i18n.input.name.placeholder"
/>
</div>
</div>

<h1>{{ i18n.title }}</h1>
<h5>{{ $t("hello", { name }).value }}</h5>

<p>
{{
$t("currentDate", { day: $t(`weekDays[${new Date().getDay()}]`) }).value
}}
</p>
<p>
{{ $t("currentDate", { day: i18n.weekDays[new Date().getDay()] }).value }}
</p>
</div>
</template>

<script>
import { useI18n, buildI18n, promisedTimeout } from "vue-composable";
import { ref, computed } from "@vue/composition-api";
export default {
setup() {
const name = ref("");
const i18n = buildI18n({
locale: "en",
fallback: "en",
messages: {
en: {
locales: {
en: "English",
pt: "Portuguese",
es: "Spanish"
},
weekDays: [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thrusday",
"Friday",
"Saturday"
],
input: {
name: {
label: "Name",
placeholder: "Your name"
}
},
hello: "Hello {name}",
currentDate: "Today is: {day}"
},
pt: {
locales: {
en: "Inglês",
pt: "Português",
es: "Espanhol"
},
weekDays: [
"Domingo",
"Segunda-feira",
"Terca-feira",
"Quarta-feira",
"Quinta-feira",
"Sexta-feira",
"Sábado"
],
input: {
name: {
label: "Nome",
placeholder: "O teu nome"
}
},
currentDate: "Hoje e': {day}",
hello: "Olá {name}"
},
// promised based
es: () =>
promisedTimeout(10).then(() => ({
locales: {
en: "Ingles",
pt: "Portugués",
es: "Espanol"
},
input: {
name: {
label: "Nombre",
placeholder: "Tu nombre"
}
},
weekDays: [
"Domingo",
"Lunes",
"Martes",
"Miércoles",
"Jueves",
"Viernes",
"Sábado"
],
hello: "Holla {name}"
}))
}
});
return {
...i18n,
name
};
}
};
</script>
4 changes: 4 additions & 0 deletions examples/vue-composable-example/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ const routes = [
{
path: "/validation",
component: () => import("./components/Validation")
},
{
path: "/i18n",
component: () => import("./components/I18n")
}
];
const router = new VueRouter({
Expand Down
20 changes: 20 additions & 0 deletions packages/core/__tests__/format/path.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,24 @@ describe("path", () => {
expect(usePath(o, "deep.b").value).toMatchObject({ a: 2 });
expect(usePath(o, "noprop.a").value).toBeUndefined();
});

it("should resolve array access", () => {
const o = {
array: [1, 2],
deep: {
x: [
1,
{
a: {
b: 1
}
}
]
}
};

expect(usePath(o, "array[0]").value).toBe(1);
expect(usePath(o, "array[1]").value).toBe(2);
expect(usePath(o, "deep.x[1].a.b").value).toBe(1);
});
});
13 changes: 9 additions & 4 deletions packages/core/__tests__/i18n/i18n.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { buildI18n } from "../../src";
import { nextTick } from "../utils";
import { ref } from "@vue/composition-api";

describe("i18n", () => {
it("should work", async () => {
Expand All @@ -10,19 +11,22 @@ describe("i18n", () => {
en: {
hello: "hello world",
helloName: "Hello {name}",
version: "My version is"
version: "My version is",
ref: ref("Hey")
},
pt: {
hello: "Olá mundo",
helloName: "Olá {name}"
helloName: "Olá {name}",
ref: ref("Boas")
}
}
});

expect(x.i18n.value).toMatchObject({
hello: "hello world",
helloName: "Hello {name}",
version: "My version is"
version: "My version is",
ref: "Hey"
});

expect(x.$t("hello").value).toBe("hello world");
Expand All @@ -38,7 +42,8 @@ describe("i18n", () => {
expect(x.i18n.value).toMatchObject({
hello: "Olá mundo",
helloName: "Olá {name}",
version: "My version is"
version: "My version is",
ref: "Boas"
});

expect(x.$t("hello").value).toBe("Olá mundo");
Expand Down
17 changes: 16 additions & 1 deletion packages/core/src/format/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,25 @@ export function usePath<T extends object = any>(
const fragments = p.split(separator);
let c = s;
for (let i = 0; i < fragments.length; i++) {
const fragmentPath = fragments[i];
let fragmentPath = fragments[i];
let index: any = -1;

if (fragmentPath[fragmentPath.length - 1] === "]") {
const m = fragmentPath.match(/\[(\d+)\]$/);
if (m && m[1]) {
index = +m[1];

fragmentPath = fragmentPath.slice(0, -m[0].length);
}
}

if (isObject(c)) {
c = c[fragmentPath];

// array like: when using ref with and array, it becomes arraylike object
if (index >= 0) {
c = (c as any)[index];
}
} else {
if (__DEV__) {
console.warn(
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/i18n/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
provide
} from "@vue/composition-api";
import { RefTyped, deepClone, isPromise, isFunction } from "../utils";
import { usePath, useFormat, FormatObject, FormatValue } from "../";
import { usePath, useFormat, FormatObject, FormatValue } from "../format";

const I18n_ACCESS_SYMBOL: InjectionKey<i18nResult<string[], string>> = Symbol(
(__DEV__ && "I18n") || ``
Expand Down
9 changes: 5 additions & 4 deletions packages/core/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,14 @@ export function deepClone<T extends object = object>(

for (let j = 0; j < keys.length; j++) {
const k = keys[j] as keyof T;
const sourceType = typeof source[k];
const v = unwrap(source[k]);
const sourceType = typeof v;
const type = typeof result[k];

if (result[k] === undefined || sourceType === type) {
result[k] = isObject(source[k])
? deepClone<any>(result[k] || {}, source[k])
: source[k];
result[k] = isObject(v)
? deepClone<any>(result[k] || {}, v)
: source[k]; // source[k] is assigned because if is ref we want to override to this ref
}
}
}
Expand Down

0 comments on commit 44b90d3

Please sign in to comment.