Skip to content

Commit 9e6f6ea

Browse files
Add support for flat json separated with dot('.') (#294)
* add function `handleFlatJson` and its test to `message-resolver` function `handleFlatJson` is use to transform flat json to normal json. * add support for flat json in i18n messages
1 parent daa288e commit 9e6f6ea

File tree

4 files changed

+106
-2
lines changed

4 files changed

+106
-2
lines changed

packages/message-resolver/src/index.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,3 +321,50 @@ export function resolveValue(obj: unknown, path: Path): PathValue {
321321

322322
return last
323323
}
324+
325+
/**
326+
* Transform flat json in obj to normal json in obj
327+
*/
328+
export function handleFlatJson(obj: unknown): unknown {
329+
// check obj
330+
if (!isObject(obj)) {
331+
return obj
332+
}
333+
334+
for (const key in obj as object) {
335+
// check key
336+
if (!obj.hasOwnProperty(key)) {
337+
continue
338+
}
339+
340+
// handle for normal json
341+
if (!key.includes(PathCharTypes.DOT)) {
342+
// recursive process value if value is also a object
343+
if (typeof obj[key] === 'object') {
344+
handleFlatJson(obj[key])
345+
}
346+
}
347+
// handle for flat json, transform to normal json
348+
else {
349+
// go to the last object
350+
const subKeys = key.split(PathCharTypes.DOT)
351+
const lastIndex = subKeys.length - 1
352+
let currentObj = obj
353+
for (let i = 0; i < lastIndex; i++) {
354+
if (!(subKeys[i] in currentObj)) {
355+
currentObj[subKeys[i]] = {}
356+
}
357+
currentObj = currentObj[subKeys[i]]
358+
}
359+
// update last object value, delete old property
360+
currentObj[subKeys[lastIndex]] = obj[key]
361+
delete obj[key]
362+
// recursive process value if value is also a object
363+
if (typeof currentObj[subKeys[lastIndex]] === 'object') {
364+
handleFlatJson(currentObj[subKeys[lastIndex]])
365+
}
366+
}
367+
}
368+
369+
return obj
370+
}

packages/message-resolver/test/index.test.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { parse, resolveValue } from '../src/index'
1+
import { parse, resolveValue, handleFlatJson } from '../src/index'
22

33
test('parse', () => {
44
expect(parse('a')).toEqual(['a'])
@@ -121,3 +121,29 @@ test('resolveValue', () => {
121121
// blanket middle
122122
expect(resolveValue({}, 'a.b.c[]d')).toEqual(null)
123123
})
124+
125+
test('handleFlatJson', () => {
126+
const obj = {
127+
a: { a1: 'a1.value' },
128+
'a.a2': 'a.a2.value',
129+
'b.x': {
130+
'b1.x': 'b1.x.value',
131+
'b2.x': ['b2.x.value0', 'b2.x.value1'],
132+
'b3.x': { 'b3.x': 'b3.x.value' }
133+
}
134+
}
135+
136+
handleFlatJson(obj)
137+
138+
expect(obj['a']['a1'] === 'a1.value').toEqual(true)
139+
// @ts-ignore
140+
expect(obj['a']['a2'] === 'a.a2.value').toEqual(true)
141+
// @ts-ignore
142+
expect(obj['b']['x']['b1']['x'] === 'b1.x.value').toEqual(true)
143+
// @ts-ignore
144+
expect(obj['b']['x']['b2']['x'][0] === 'b2.x.value0').toEqual(true)
145+
// @ts-ignore
146+
expect(obj['b']['x']['b2']['x'][1] === 'b2.x.value1').toEqual(true)
147+
// @ts-ignore
148+
expect(obj['b']['x']['b3']['x']['b3']['x'] === 'b3.x.value').toEqual(true)
149+
})

packages/vue-i18n/src/composer.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ import {
3232
parseNumberArgs,
3333
clearNumberFormat,
3434
NOT_REOSLVED,
35-
DevToolsTimelineEvents
35+
DevToolsTimelineEvents,
36+
handleFlatJson
3637
} from '@intlify/core-base'
3738
import { I18nWarnCodes, getWarnMessage } from './warnings'
3839
import { I18nErrorCodes, createI18nError } from './errors'
@@ -959,6 +960,13 @@ export function getLocaleMessages<Message = VueMessageType>(
959960
})
960961
}
961962

963+
// handle messages for flat json
964+
for (const key in ret) {
965+
if (ret.hasOwnProperty(key)) {
966+
handleFlatJson(ret[key])
967+
}
968+
}
969+
962970
return ret
963971
}
964972

packages/vue-i18n/test/i18n.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,29 @@ describe('createI18n', () => {
2727

2828
expect(i18n.mode).toEqual('composition')
2929
})
30+
31+
test('flat json message in legacy mode', () => {
32+
const i18n = createI18n({
33+
messages: {
34+
en: { 'mainMenu.buttonStart': 'Start!' }
35+
}
36+
})
37+
const messages = i18n.global.messages
38+
// @ts-ignore
39+
expect(messages['en']['mainMenu']['buttonStart'] === 'Start!').toEqual(true)
40+
})
41+
42+
test('flat json message in composition mode', () => {
43+
const i18n = createI18n({
44+
legacy: false,
45+
messages: {
46+
en: { 'mainMenu.buttonStart': 'Start!' }
47+
}
48+
})
49+
const messages = i18n.global.messages.value
50+
// @ts-ignore
51+
expect(messages['en']['mainMenu']['buttonStart'] === 'Start!').toEqual(true)
52+
})
3053
})
3154

3255
describe('useI18n', () => {

0 commit comments

Comments
 (0)