mirror of
https://github.com/cupcakearmy/svelte-i18n.git
synced 2024-11-16 18:10:43 +01:00
Namespace i18n store methods with "i18n" property
This commit is contained in:
parent
1e8597150c
commit
07691f3a6d
@ -2,3 +2,4 @@
|
||||
/.*
|
||||
/yarn.lock
|
||||
/package-lock.json
|
||||
/src
|
55
README.md
55
README.md
@ -12,60 +12,55 @@
|
||||
import i18n from 'svelte-i18n'
|
||||
import { Store } from 'svelte/store'
|
||||
|
||||
const store = new Store()
|
||||
|
||||
/** i18n(svelteStore, arrayOfLocalesObjects) */
|
||||
i18n(store, [
|
||||
{
|
||||
/** i18n(svelteStore, { dictionary }) */
|
||||
const store = i18n(new Store(), {
|
||||
dictionary: {
|
||||
'pt-BR': {
|
||||
message: 'Mensagem',
|
||||
messages: {
|
||||
alert: 'Alerta',
|
||||
error: 'Erro'
|
||||
}
|
||||
error: 'Erro',
|
||||
},
|
||||
},
|
||||
'en-US': {
|
||||
message: 'Message',
|
||||
messages: {
|
||||
alert: 'Alert',
|
||||
error: 'Error'
|
||||
}
|
||||
}
|
||||
error: 'Error',
|
||||
},
|
||||
/** Locales are deeply merged */
|
||||
{
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
/**
|
||||
* Extend the initial dictionary.
|
||||
* Dictionaries are deeply merged.
|
||||
* */
|
||||
store.i18n.extendDictionary({
|
||||
'pt-BR': {
|
||||
messages: {
|
||||
warn: 'Aviso',
|
||||
success: 'Sucesso'
|
||||
}
|
||||
success: 'Sucesso',
|
||||
},
|
||||
},
|
||||
'en-US': {
|
||||
messages: {
|
||||
warn: 'Warn',
|
||||
success: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
success: 'Success',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
/** Set the initial locale */
|
||||
store.i18n.setLocale('en-US')
|
||||
```
|
||||
|
||||
### On `templates`
|
||||
|
||||
```html
|
||||
|
||||
<div>
|
||||
{$_('message')}: {upper($_('messages.success'))}
|
||||
{$_('message')}: {$_.upper('messages.success'))}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import { upper } from 'svelte-i18n';
|
||||
export default {
|
||||
helpers: {
|
||||
upper,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
Renders:
|
||||
|
3676
package-lock.json
generated
3676
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
33
package.json
33
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "svelte-i18n",
|
||||
"version": "0.0.0",
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"main": "dist/i18n.js",
|
||||
"types": "src/index.d.ts",
|
||||
@ -13,9 +13,9 @@
|
||||
"start": "microbundle watch --name='svelte-i18n'",
|
||||
"test": "jest --no-cache --verbose",
|
||||
"test:watch": "jest --no-cache --verbose --watchAll",
|
||||
"lint": "eslint \"*.js\" \"src/**/*.js\"",
|
||||
"format": "prettier --loglevel silent --write \"*.js\" \"src/**/*.js\" && eslint --fix \"*.js\" \"src/**/*.js\"",
|
||||
"prepublishOnly": "npm run format && npm run test"
|
||||
"lint": "eslint \"src/**/*.js\"",
|
||||
"format": "prettier --loglevel silent --write \"src/**/*.js\" && eslint --fix \"src/**/*.js\"",
|
||||
"prepublishOnly": "npm run format && npm run test && npm run build"
|
||||
},
|
||||
"jest": {
|
||||
"verbose": true,
|
||||
@ -29,7 +29,8 @@
|
||||
],
|
||||
"coveragePathIgnorePatterns": [
|
||||
"/node_modules/",
|
||||
"/test/"
|
||||
"/test/",
|
||||
"/src/formatter.js"
|
||||
],
|
||||
"coverageThreshold": {
|
||||
"global": {
|
||||
@ -43,26 +44,26 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.0.0-beta.56",
|
||||
"@babel/preset-env": "^7.0.0-beta.56",
|
||||
"babel-core": "^7.0.0-bridge.0",
|
||||
"babel-jest": "^23.4.2",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint": "^5.3.0",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-config-standard": "^11.0.0",
|
||||
"eslint-plugin-import": "^2.11.0",
|
||||
"eslint-plugin-node": "^6.0.1",
|
||||
"eslint-plugin-prettier": "^2.6.0",
|
||||
"eslint-plugin-promise": "^3.7.0",
|
||||
"eslint-plugin-import": "^2.13.0",
|
||||
"eslint-plugin-node": "^7.0.1",
|
||||
"eslint-plugin-prettier": "^2.6.2",
|
||||
"eslint-plugin-promise": "^3.8.0",
|
||||
"eslint-plugin-standard": "^3.1.0",
|
||||
"jest": "^22.4.3",
|
||||
"microbundle": "^0.4.4",
|
||||
"prettier": "^1.12.1",
|
||||
"svelte": "^2.9.10"
|
||||
"jest": "^23.4.2",
|
||||
"microbundle": "^0.6.0",
|
||||
"prettier": "^1.14.1",
|
||||
"svelte": "^2.9.11"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^2.9.10"
|
||||
"svelte": "^2.9.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/preset-env": "^7.0.0-beta.56",
|
||||
"deepmerge": "^2.1.1",
|
||||
"object-resolve-path": "^1.1.1"
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
/* istanbul ignore */
|
||||
/**
|
||||
* Adapted from 'https://github.com/kazupon/vue-i18n/blob/dev/src/format.js'
|
||||
* Copyright (c) 2016 kazuya kawaguchi
|
||||
**/
|
||||
import { isObject, warn } from './utils'
|
||||
import { isObject } from './utils'
|
||||
|
||||
const RE_TOKEN_LIST_VALUE = /^(\d)+/
|
||||
const RE_TOKEN_NAMED_VALUE = /^(\w)+/
|
||||
@ -79,7 +80,11 @@ export function compile(tokens, values) {
|
||||
const compiled = []
|
||||
let index = 0
|
||||
|
||||
const mode = Array.isArray(values) ? 'list' : isObject(values) ? 'named' : 'unknown'
|
||||
const mode = Array.isArray(values)
|
||||
? 'list'
|
||||
: isObject(values)
|
||||
? 'named'
|
||||
: 'unknown'
|
||||
|
||||
if (mode === 'unknown') {
|
||||
return compiled
|
||||
@ -99,14 +104,18 @@ export function compile(tokens, values) {
|
||||
compiled.push(values[token.value])
|
||||
} else {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warn(`Type of token '${token.type}' and format of value '${mode}' don't match!`)
|
||||
console.warn(
|
||||
`[svelte-i18n] Type of token '${
|
||||
token.type
|
||||
}' and format of value '${mode}' don't match!`,
|
||||
)
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
case 'unknown':
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warn(`Detect 'unknown' type of token!`)
|
||||
console.warn(`[svelte-i18n] Detect 'unknown' type of token!`)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
30
src/index.js
30
src/index.js
@ -1,12 +1,11 @@
|
||||
|
||||
import deepmerge from 'deepmerge'
|
||||
import resolvePath from 'object-resolve-path'
|
||||
import { capital, title, upper, lower } from './utils'
|
||||
import Formatter from './formatter'
|
||||
|
||||
const resolvePath = a => a
|
||||
|
||||
export function i18n(store, localesList) {
|
||||
export function i18n(store, { dictionary }) {
|
||||
const formatter = new Formatter()
|
||||
const locales = {} // deepmerge.all(localesList)
|
||||
let dictionaries = {}
|
||||
let currentLocale
|
||||
|
||||
const getLocalizedMessage = (
|
||||
@ -15,7 +14,7 @@ export function i18n(store, localesList) {
|
||||
locale = currentLocale,
|
||||
transformers = undefined,
|
||||
) => {
|
||||
let message = resolvePath(locales[locale], path)
|
||||
let message = resolvePath(dictionaries[locale], path)
|
||||
|
||||
if (!message) return path
|
||||
|
||||
@ -47,17 +46,32 @@ export function i18n(store, localesList) {
|
||||
},
|
||||
plural(path, counter, interpolations, locale) {
|
||||
return getLocalizedMessage(path, interpolations, locale, [
|
||||
message => message.split('|')[Math.min(Math.abs(counter), 2)],
|
||||
message => {
|
||||
const choice =
|
||||
typeof counter === 'number' ? Math.min(Math.abs(counter), 2) : 0
|
||||
return message.split('|')[choice]
|
||||
},
|
||||
])
|
||||
},
|
||||
}
|
||||
|
||||
store.setLocale = locale => store.fire('locale', locale)
|
||||
store.i18n = {
|
||||
setLocale(locale) {
|
||||
store.fire('locale', locale)
|
||||
},
|
||||
extendDictionary(...list) {
|
||||
dictionaries = deepmerge.all([dictionaries, ...list])
|
||||
},
|
||||
}
|
||||
|
||||
store.i18n.extendDictionary(dictionary)
|
||||
|
||||
store.on('locale', newLocale => {
|
||||
currentLocale = newLocale
|
||||
const _ = getLocalizedMessage
|
||||
|
||||
Object.assign(_, utilities)
|
||||
|
||||
store.set({ locale: newLocale, _ })
|
||||
})
|
||||
|
||||
|
19
src/utils.js
19
src/utils.js
@ -1,15 +1,6 @@
|
||||
export const capital = (str) => str.replace(/(^|\s)\S/, l => l.toUpperCase())
|
||||
export const title = (str) => str.replace(/(^|\s)\S/g, l => l.toUpperCase())
|
||||
export const upper = (str) => str.toLocaleUpperCase()
|
||||
export const lower = (str) => str.toLocaleLowerCase()
|
||||
export const capital = str => str.replace(/(^|\s)\S/, l => l.toUpperCase())
|
||||
export const title = str => str.replace(/(^|\s)\S/g, l => l.toUpperCase())
|
||||
export const upper = str => str.toLocaleUpperCase()
|
||||
export const lower = str => str.toLocaleLowerCase()
|
||||
|
||||
export const isObject = (obj) => obj !== null && typeof obj === 'object'
|
||||
|
||||
export function warn(msg, err) {
|
||||
if (typeof console !== 'undefined') {
|
||||
console.warn(`[svelte-i18n] ${msg}`)
|
||||
if (err) {
|
||||
console.warn(err.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
export const isObject = obj => obj !== null && typeof obj === 'object'
|
||||
|
@ -1,6 +1,8 @@
|
||||
// TODO: A more serious test
|
||||
|
||||
import { i18n } from '../src/index'
|
||||
import { Store } from 'svelte/store.umd'
|
||||
import { capital, title, upper, lower, isObject } from '../src/utils'
|
||||
import { capital, title, upper, lower, isObject, warn } from '../src/utils'
|
||||
|
||||
const store = new Store()
|
||||
const locales = {
|
||||
@ -11,31 +13,23 @@ const locales = {
|
||||
pluralization: 'Zero | Um | Muito!',
|
||||
interpolation: {
|
||||
key: 'Olá, {0}! Como está {1}?',
|
||||
named: 'Olá, {name}! Como está {time}?'
|
||||
named: 'Olá, {name}! Como está {time}?',
|
||||
},
|
||||
wow: {
|
||||
much: {
|
||||
deep: {
|
||||
list: ['Muito', 'muito profundo']
|
||||
}
|
||||
}
|
||||
list: ['Muito', 'muito profundo'],
|
||||
},
|
||||
},
|
||||
},
|
||||
obj: {
|
||||
a: 'a'
|
||||
}
|
||||
}
|
||||
a: 'a',
|
||||
b: 'b',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
i18n(store, [
|
||||
locales,
|
||||
{
|
||||
'pt-br': {
|
||||
obj: {
|
||||
b: 'b'
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
i18n(store, { dictionary: locales })
|
||||
|
||||
/**
|
||||
* Dummy test
|
||||
@ -62,18 +56,18 @@ describe('Localization', () => {
|
||||
expect(_).toBeInstanceOf(Function)
|
||||
})
|
||||
|
||||
it('should have a .setLocale() method', () => {
|
||||
expect(store.setLocale).toBeInstanceOf(Function)
|
||||
it('should have a .i18n.setLocale() method', () => {
|
||||
expect(store.i18n.setLocale).toBeInstanceOf(Function)
|
||||
|
||||
store.setLocale('pt-br')
|
||||
store.i18n.setLocale('pt-br')
|
||||
const { locale } = store.get()
|
||||
|
||||
expect(locale).toBe('pt-br')
|
||||
})
|
||||
|
||||
it('should return the message id when no message identified by it was found', () => {
|
||||
store.setLocale('pt-br')
|
||||
const { locale, _ } = store.get()
|
||||
store.i18n.setLocale('pt-br')
|
||||
const { _ } = store.get()
|
||||
|
||||
expect(_('non.existent')).toBe('non.existent')
|
||||
})
|
||||
@ -84,15 +78,15 @@ describe('Localization', () => {
|
||||
})
|
||||
|
||||
it('should get a deep nested message by its string path', () => {
|
||||
store.setLocale('pt-br')
|
||||
const { locale, _ } = store.get()
|
||||
store.i18n.setLocale('pt-br')
|
||||
const { _ } = store.get()
|
||||
|
||||
expect(_('obj.b')).toBe('b')
|
||||
})
|
||||
|
||||
it('should get a message within an array by its index', () => {
|
||||
store.setLocale('pt-br')
|
||||
const { locale, _ } = store.get()
|
||||
store.i18n.setLocale('pt-br')
|
||||
const { _ } = store.get()
|
||||
|
||||
expect(_('phrases[1]')).toBe(locales['pt-br'].phrases[1])
|
||||
|
||||
@ -101,28 +95,31 @@ describe('Localization', () => {
|
||||
})
|
||||
|
||||
it('should interpolate with {numeric} placeholders', () => {
|
||||
store.setLocale('pt-br')
|
||||
const { locale, _ } = store.get()
|
||||
store.i18n.setLocale('pt-br')
|
||||
const { _ } = store.get()
|
||||
|
||||
expect(_('interpolation.key', ['Chris', 'o dia'])).toBe('Olá, Chris! Como está o dia?')
|
||||
expect(_('interpolation.key', ['Chris', 'o dia'])).toBe(
|
||||
'Olá, Chris! Como está o dia?',
|
||||
)
|
||||
})
|
||||
|
||||
it('should interpolate with {named} placeholders', () => {
|
||||
store.setLocale('pt-br')
|
||||
const { locale, _ } = store.get()
|
||||
store.i18n.setLocale('pt-br')
|
||||
const { _ } = store.get()
|
||||
|
||||
expect(
|
||||
_('interpolation.named', {
|
||||
name: 'Chris',
|
||||
time: 'o dia'
|
||||
})
|
||||
time: 'o dia',
|
||||
}),
|
||||
).toBe('Olá, Chris! Como está o dia?')
|
||||
})
|
||||
|
||||
it('should handle pluralization with _.plural()', () => {
|
||||
store.setLocale('pt-br')
|
||||
const { locale, _ } = store.get()
|
||||
store.i18n.setLocale('pt-br')
|
||||
const { _ } = store.get()
|
||||
|
||||
expect(_.plural('pluralization')).toBe('Zero')
|
||||
expect(_.plural('pluralization', 0)).toBe('Zero')
|
||||
expect(_.plural('pluralization', 1)).toBe('Um')
|
||||
expect(_.plural('pluralization', -1)).toBe('Um')
|
||||
@ -134,7 +131,7 @@ describe('Localization', () => {
|
||||
|
||||
describe('Localization utilities', () => {
|
||||
it('should capital a translated message', () => {
|
||||
store.setLocale('pt-br')
|
||||
store.i18n.setLocale('pt-br')
|
||||
const { _ } = store.get()
|
||||
|
||||
expect(capital('Adoro banana')).toBe('Adoro banana')
|
||||
@ -142,7 +139,7 @@ describe('Localization utilities', () => {
|
||||
})
|
||||
|
||||
it('should title a translated message', () => {
|
||||
store.setLocale('pt-br')
|
||||
store.i18n.setLocale('pt-br')
|
||||
const { _ } = store.get()
|
||||
|
||||
expect(title('Adoro Banana')).toBe('Adoro Banana')
|
||||
@ -150,7 +147,7 @@ describe('Localization utilities', () => {
|
||||
})
|
||||
|
||||
it('should lowercase a translated message', () => {
|
||||
store.setLocale('pt-br')
|
||||
store.i18n.setLocale('pt-br')
|
||||
const { _ } = store.get()
|
||||
|
||||
expect(lower('adoro banana')).toBe('adoro banana')
|
||||
@ -158,7 +155,7 @@ describe('Localization utilities', () => {
|
||||
})
|
||||
|
||||
it('should uppercase a translated message', () => {
|
||||
store.setLocale('pt-br')
|
||||
store.i18n.setLocale('pt-br')
|
||||
const { _ } = store.get()
|
||||
|
||||
expect(upper('ADORO BANANA')).toBe('ADORO BANANA')
|
||||
|
Loading…
Reference in New Issue
Block a user