Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for flat json separated with dot('.') #402

Merged
merged 1 commit into from
Mar 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 48 additions & 1 deletion packages/message-resolver/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isObject } from '@intlify/shared'
import { isObject, hasOwn } from '@intlify/shared'

/** @VueI18nGeneral */
export type Path = string
Expand Down Expand Up @@ -321,3 +321,50 @@ export function resolveValue(obj: unknown, path: Path): PathValue {

return last
}

/**
* Transform flat json in obj to normal json in obj
*/
export function handleFlatJson(obj: unknown): unknown {
// check obj
if (!isObject(obj)) {
return obj
}

for (const key in obj as object) {
// check key
if (!hasOwn(obj, key)) {
continue
}

// handle for normal json
if (!key.includes(PathCharTypes.DOT)) {
// recursive process value if value is also a object
if (isObject(obj[key])) {
handleFlatJson(obj[key])
}
}
// handle for flat json, transform to normal json
else {
// go to the last object
const subKeys = key.split(PathCharTypes.DOT)
const lastIndex = subKeys.length - 1
let currentObj = obj
for (let i = 0; i < lastIndex; i++) {
if (!(subKeys[i] in currentObj)) {
currentObj[subKeys[i]] = {}
}
currentObj = currentObj[subKeys[i]]
}
// update last object value, delete old property
currentObj[subKeys[lastIndex]] = obj[key]
delete obj[key]
// recursive process value if value is also a object
if (isObject(currentObj[subKeys[lastIndex]])) {
handleFlatJson(currentObj[subKeys[lastIndex]])
}
}
}

return obj
}
28 changes: 27 additions & 1 deletion packages/message-resolver/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { parse, resolveValue } from '../src/index'
import { parse, resolveValue, handleFlatJson } from '../src/index'

test('parse', () => {
expect(parse('a')).toEqual(['a'])
Expand Down Expand Up @@ -121,3 +121,29 @@ test('resolveValue', () => {
// blanket middle
expect(resolveValue({}, 'a.b.c[]d')).toEqual(null)
})

test('handleFlatJson', () => {
const obj = {
a: { a1: 'a1.value' },
'a.a2': 'a.a2.value',
'b.x': {
'b1.x': 'b1.x.value',
'b2.x': ['b2.x.value0', 'b2.x.value1'],
'b3.x': { 'b3.x': 'b3.x.value' }
}
}
const expectObj = {
a: {
a1: 'a1.value',
a2: 'a.a2.value'
},
b: {
x: {
b1: { x: 'b1.x.value' },
b2: { x: ['b2.x.value0', 'b2.x.value1'] },
b3: { x: { b3: { x: 'b3.x.value' } } }
}
}
}
expect(handleFlatJson(obj)).toEqual(expectObj)
})
5 changes: 5 additions & 0 deletions packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ export function escapeHtml(rawText: string): string {
.replace(/'/g, '&apos;')
}

const hasOwnProperty = Object.prototype.hasOwnProperty
export function hasOwn(obj: object | Array<any>, key: string): boolean {
return hasOwnProperty.call(obj, key)
}

/* eslint-enable */

/**
Expand Down
29 changes: 21 additions & 8 deletions packages/vue-i18n/src/composer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
isBoolean,
isPlainObject,
makeSymbol,
isObject
isObject,
hasOwn
} from '@intlify/shared'
import {
isTranslateFallbackWarn,
Expand All @@ -34,7 +35,8 @@ import {
parseNumberArgs,
clearNumberFormat,
NOT_REOSLVED,
DevToolsTimelineEvents
DevToolsTimelineEvents,
handleFlatJson
} from '@intlify/core-base'
import { I18nWarnCodes, getWarnMessage } from './warnings'
import { I18nErrorCodes, createI18nError } from './errors'
Expand Down Expand Up @@ -161,6 +163,13 @@ export interface ComposerOptions<Message = VueMessageType> {
* @defaultValue `{}`
*/
messages?: LocaleMessages<Message>
/**
* @remarks
* Allow use flat json messages or not
*
* @defaultValue `false`
*/
flatJson?: boolean
/**
* @remarks
* The datetime formats of localization.
Expand Down Expand Up @@ -936,6 +945,7 @@ function defineCoreMissingHandler<Message = VueMessageType>(
type GetLocaleMessagesOptions<Message = VueMessageType> = {
messages?: LocaleMessages<Message>
__i18n?: CustomBlocks<Message>
flatJson?: boolean
}

export function getLocaleMessages<Message = VueMessageType>(
Expand Down Expand Up @@ -963,13 +973,16 @@ export function getLocaleMessages<Message = VueMessageType>(
})
}

return ret
}
// handle messages for flat json
if (options.flatJson) {
for (const key in ret) {
if (hasOwn(ret, key)) {
handleFlatJson(ret[key])
}
}
}

const hasOwnProperty = Object.prototype.hasOwnProperty
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function hasOwn(obj: object | Array<any>, key: string): boolean {
return hasOwnProperty.call(obj, key)
return ret
}

const isNotObjectOrIsArray = (val: unknown) => !isObject(val) || isArray(val)
Expand Down
9 changes: 9 additions & 0 deletions packages/vue-i18n/src/legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ export interface VueI18nOptions {
* @defaultValue `{}`
*/
messages?: LocaleMessages<VueMessageType>
/**
* @remarks
* Allow use flat json messages or not
*
* @defaultValue `false`
*/
flatJson?: boolean
/**
* @remarks
* The datetime formats of localization.
Expand Down Expand Up @@ -964,11 +971,13 @@ function convertComposerOptions<

const datetimeFormats = options.datetimeFormats
const numberFormats = options.numberFormats
const flatJson = options.flatJson

return {
locale,
fallbackLocale,
messages,
flatJson,
datetimeFormats,
numberFormats,
missing,
Expand Down
27 changes: 27 additions & 0 deletions packages/vue-i18n/test/i18n.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,33 @@ describe('createI18n', () => {
})
})

describe('createI18n with flat json messages', () => {
test('legacy mode', () => {
const i18n = createI18n({
flatJson: true,
messages: {
en: { 'mainMenu.buttonStart': 'Start!' }
}
})
const messages = i18n.global.messages
// @ts-ignore
expect(messages.en.mainMenu.buttonStart).toEqual('Start!')
})

test('composition mode', () => {
const i18n = createI18n({
legacy: false,
flatJson: true,
messages: {
en: { 'mainMenu.buttonStart': 'Start!' }
}
})
const messages = i18n.global.messages.value
// @ts-ignore
expect(messages.en.mainMenu.buttonStart).toEqual('Start!')
})
})

describe('useI18n', () => {
let org: any // eslint-disable-line @typescript-eslint/no-explicit-any
let spy: any // eslint-disable-line @typescript-eslint/no-explicit-any
Expand Down