i18n-js 4.0.1 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby-tests.yml +22 -1
- data/.gitignore +2 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +24 -2
- data/MIGRATING_FROM_V3_TO_V4.md +1 -1
- data/README.md +267 -9
- data/bin/release +81 -0
- data/i18n-js.gemspec +4 -1
- data/lib/i18n-js/cli/check_command.rb +7 -147
- data/lib/i18n-js/cli/command.rb +10 -0
- data/lib/i18n-js/cli/lint_scripts_command.rb +157 -0
- data/lib/i18n-js/cli/lint_translations_command.rb +155 -0
- data/lib/i18n-js/cli/plugins_command.rb +67 -0
- data/lib/i18n-js/cli.rb +12 -1
- data/lib/i18n-js/embed_fallback_translations_plugin.rb +59 -0
- data/lib/i18n-js/export_files_plugin.rb +97 -0
- data/lib/i18n-js/lint.js +150645 -0
- data/lib/i18n-js/lint.ts +196 -0
- data/lib/i18n-js/listen.rb +3 -2
- data/lib/i18n-js/plugin.rb +66 -0
- data/lib/i18n-js/schema.rb +53 -14
- data/lib/i18n-js/version.rb +1 -1
- data/lib/i18n-js.rb +24 -3
- data/package.json +10 -0
- metadata +33 -9
data/lib/i18n-js/lint.ts
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
import { readFileSync, statSync } from "fs";
|
2
|
+
import * as ts from "typescript";
|
3
|
+
import { glob } from "glob";
|
4
|
+
|
5
|
+
type ScopeInfo = {
|
6
|
+
type: "default" | "scope" | "base";
|
7
|
+
location: string;
|
8
|
+
base: string | null;
|
9
|
+
full: string;
|
10
|
+
scope: string;
|
11
|
+
};
|
12
|
+
|
13
|
+
function location(node: ts.Node, append: string = ":") {
|
14
|
+
const sourceFile = node.getSourceFile();
|
15
|
+
let { line, character } = sourceFile.getLineAndCharacterOfPosition(
|
16
|
+
node.getStart(sourceFile)
|
17
|
+
);
|
18
|
+
|
19
|
+
line += 1;
|
20
|
+
character += 1;
|
21
|
+
const file = sourceFile.fileName;
|
22
|
+
const location = `${file}:${line}:${character}`;
|
23
|
+
|
24
|
+
return `${location}${append}`;
|
25
|
+
}
|
26
|
+
|
27
|
+
const callExpressions = ["t", "i18n.t", "i18n.translate"];
|
28
|
+
|
29
|
+
function tsKind(node: ts.Node) {
|
30
|
+
const keys = Object.keys(ts.SyntaxKind);
|
31
|
+
const values = Object.values(ts.SyntaxKind);
|
32
|
+
|
33
|
+
return keys[values.indexOf(node.kind)];
|
34
|
+
}
|
35
|
+
|
36
|
+
function getTranslationScopesFromFile(filePath: string) {
|
37
|
+
const scopes: ScopeInfo[] = [];
|
38
|
+
|
39
|
+
const sourceFile = ts.createSourceFile(
|
40
|
+
filePath,
|
41
|
+
readFileSync(filePath).toString(),
|
42
|
+
ts.ScriptTarget.ES2015,
|
43
|
+
true
|
44
|
+
);
|
45
|
+
|
46
|
+
inspect(sourceFile);
|
47
|
+
|
48
|
+
return scopes;
|
49
|
+
|
50
|
+
function inspect(node: ts.Node) {
|
51
|
+
const next = () => {
|
52
|
+
ts.forEachChild(node, inspect);
|
53
|
+
};
|
54
|
+
|
55
|
+
if (node.kind !== ts.SyntaxKind.CallExpression) {
|
56
|
+
return next();
|
57
|
+
}
|
58
|
+
|
59
|
+
const expr = node.getChildAt(0).getText();
|
60
|
+
const text = JSON.stringify(node.getText(sourceFile));
|
61
|
+
|
62
|
+
if (!callExpressions.includes(expr)) {
|
63
|
+
return next();
|
64
|
+
}
|
65
|
+
|
66
|
+
const syntaxList = node.getChildAt(2);
|
67
|
+
|
68
|
+
if (!syntaxList.getText().trim()) {
|
69
|
+
return next();
|
70
|
+
}
|
71
|
+
|
72
|
+
const scopeNode = syntaxList.getChildAt(0) as ts.StringLiteral;
|
73
|
+
const optionsNode = syntaxList.getChildAt(2) as ts.ObjectLiteralExpression;
|
74
|
+
|
75
|
+
if (scopeNode.kind !== ts.SyntaxKind.StringLiteral) {
|
76
|
+
return next();
|
77
|
+
}
|
78
|
+
|
79
|
+
if (
|
80
|
+
optionsNode &&
|
81
|
+
optionsNode.kind !== ts.SyntaxKind.ObjectLiteralExpression
|
82
|
+
) {
|
83
|
+
return next();
|
84
|
+
}
|
85
|
+
|
86
|
+
if (!optionsNode) {
|
87
|
+
scopes.push({
|
88
|
+
type: "scope",
|
89
|
+
scope: scopeNode.text,
|
90
|
+
base: null,
|
91
|
+
full: scopeNode.text,
|
92
|
+
location: location(node, ""),
|
93
|
+
});
|
94
|
+
return next();
|
95
|
+
}
|
96
|
+
|
97
|
+
scopes.push(...getScopes(scopeNode, optionsNode));
|
98
|
+
}
|
99
|
+
|
100
|
+
function mapProperties(node: ts.ObjectLiteralExpression): {
|
101
|
+
name: string;
|
102
|
+
value: ts.Node;
|
103
|
+
}[] {
|
104
|
+
return node.properties.map((p) => ({
|
105
|
+
name: (p.name as ts.Identifier).escapedText.toString(),
|
106
|
+
value: p.getChildAt(2),
|
107
|
+
}));
|
108
|
+
}
|
109
|
+
|
110
|
+
function getScopes(
|
111
|
+
scopeNode: ts.StringLiteral,
|
112
|
+
node: ts.ObjectLiteralExpression
|
113
|
+
): ScopeInfo[] {
|
114
|
+
const suffix = scopeNode.text;
|
115
|
+
|
116
|
+
const result: ScopeInfo[] = [];
|
117
|
+
const properties = mapProperties(node);
|
118
|
+
|
119
|
+
if (
|
120
|
+
properties.length === 0 ||
|
121
|
+
!properties.some((p) => p.name === "scope")
|
122
|
+
) {
|
123
|
+
result.push({
|
124
|
+
type: "scope",
|
125
|
+
scope: suffix,
|
126
|
+
base: null,
|
127
|
+
full: suffix,
|
128
|
+
location: location(scopeNode, ""),
|
129
|
+
});
|
130
|
+
}
|
131
|
+
|
132
|
+
properties.forEach((property) => {
|
133
|
+
if (
|
134
|
+
property.name === "scope" &&
|
135
|
+
property.value.kind === ts.SyntaxKind.StringLiteral
|
136
|
+
) {
|
137
|
+
const base = (property.value as ts.StringLiteral).text;
|
138
|
+
|
139
|
+
result.push({
|
140
|
+
type: "base",
|
141
|
+
scope: suffix,
|
142
|
+
base,
|
143
|
+
full: `${base}.${suffix}`,
|
144
|
+
location: location(scopeNode, ""),
|
145
|
+
});
|
146
|
+
}
|
147
|
+
|
148
|
+
if (
|
149
|
+
property.name === "defaults" &&
|
150
|
+
property.value.kind === ts.SyntaxKind.ArrayLiteralExpression
|
151
|
+
) {
|
152
|
+
const op = property.value as ts.ArrayLiteralExpression;
|
153
|
+
const values = op.getChildAt(1);
|
154
|
+
const objects = (
|
155
|
+
values
|
156
|
+
.getChildren()
|
157
|
+
.filter(
|
158
|
+
(n) => n.kind === ts.SyntaxKind.ObjectLiteralExpression
|
159
|
+
) as ts.ObjectLiteralExpression[]
|
160
|
+
).map(mapProperties);
|
161
|
+
|
162
|
+
objects.forEach((object) => {
|
163
|
+
object.forEach((prop) => {
|
164
|
+
if (
|
165
|
+
prop.name === "scope" &&
|
166
|
+
prop.value.kind === ts.SyntaxKind.StringLiteral
|
167
|
+
) {
|
168
|
+
const text = (prop.value as ts.StringLiteral).text;
|
169
|
+
|
170
|
+
result.push({
|
171
|
+
type: "default",
|
172
|
+
scope: text,
|
173
|
+
base: null,
|
174
|
+
full: text,
|
175
|
+
location: location(prop.value, ""),
|
176
|
+
});
|
177
|
+
}
|
178
|
+
});
|
179
|
+
});
|
180
|
+
}
|
181
|
+
});
|
182
|
+
|
183
|
+
return result;
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
const patterns = (
|
188
|
+
process.argv[2] ??
|
189
|
+
"!(node_modules)/**/*.js:!(node_modules)/**/*.ts:!(node_modules)/**/*.jsx:!(node_modules)/**/*.tsx"
|
190
|
+
).split(":");
|
191
|
+
const files = patterns.flatMap((pattern) => glob.sync(pattern));
|
192
|
+
const scopes = files
|
193
|
+
.filter((filePath) => statSync(filePath).isFile())
|
194
|
+
.flatMap((path) => getTranslationScopesFromFile(path));
|
195
|
+
|
196
|
+
console.log(JSON.stringify(scopes, null, 2));
|
data/lib/i18n-js/listen.rb
CHANGED
@@ -8,6 +8,7 @@ module I18nJS
|
|
8
8
|
def self.listen(
|
9
9
|
config_file: Rails.root.join("config/i18n.yml"),
|
10
10
|
locales_dir: Rails.root.join("config/locales"),
|
11
|
+
run_on_start: true,
|
11
12
|
options: {}
|
12
13
|
)
|
13
14
|
return unless Rails.env.development?
|
@@ -19,7 +20,7 @@ module I18nJS
|
|
19
20
|
|
20
21
|
self.started = true
|
21
22
|
|
22
|
-
locales_dirs = Array(locales_dir)
|
23
|
+
locales_dirs = Array(locales_dir).map {|path| File.expand_path(path) }
|
23
24
|
|
24
25
|
relative_paths =
|
25
26
|
[config_file, *locales_dirs].map {|path| relative_path(path) }
|
@@ -27,7 +28,7 @@ module I18nJS
|
|
27
28
|
debug("Watching #{relative_paths.inspect}")
|
28
29
|
|
29
30
|
listener(config_file, locales_dirs.map(&:to_s), options).start
|
30
|
-
I18nJS.call(config_file: config_file)
|
31
|
+
I18nJS.call(config_file: config_file) if run_on_start
|
31
32
|
end
|
32
33
|
|
33
34
|
def self.relative_path(path)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "schema"
|
4
|
+
|
5
|
+
module I18nJS
|
6
|
+
def self.plugins
|
7
|
+
@plugins ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.register_plugin(plugin)
|
11
|
+
plugins << plugin
|
12
|
+
plugin.setup
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.plugin_files
|
16
|
+
Gem.find_files("i18n-js/*_plugin.rb")
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.load_plugins!
|
20
|
+
plugin_files.each do |path|
|
21
|
+
require path
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Plugin
|
26
|
+
# This method is responsible for transforming the translations. The
|
27
|
+
# translations you'll receive may be already be filtered by other plugins
|
28
|
+
# and by the default filtering itself. If you need to access the original
|
29
|
+
# translations, use `I18nJS.translations`.
|
30
|
+
#
|
31
|
+
# Make sure you always check whether your plugin is active before
|
32
|
+
# transforming translations; otherwise, opting out transformation won't be
|
33
|
+
# possible.
|
34
|
+
def self.transform(translations:, config:) # rubocop:disable Lint/UnusedMethodArgument
|
35
|
+
translations
|
36
|
+
end
|
37
|
+
|
38
|
+
# In case your plugin accepts configuration, this is where you must validate
|
39
|
+
# the configuration, making sure only valid keys and type is provided.
|
40
|
+
# If the configuration contains invalid data, then you must raise an
|
41
|
+
# exception using something like
|
42
|
+
# `raise I18nJS::Schema::InvalidError, error_message`.
|
43
|
+
def self.validate_schema(config:)
|
44
|
+
end
|
45
|
+
|
46
|
+
# This method must set up the basic plugin configuration, like adding the
|
47
|
+
# config's root key in case your plugin accepts configuration (defined via
|
48
|
+
# the config file).
|
49
|
+
#
|
50
|
+
# If you don't add this key, the linter will prevent non-default keys from
|
51
|
+
# being added to the configuration file.
|
52
|
+
def self.setup
|
53
|
+
end
|
54
|
+
|
55
|
+
# This method is called whenever `I18nJS.call(**kwargs)` finishes exporting
|
56
|
+
# JSON files based on your configuration.
|
57
|
+
#
|
58
|
+
# You can use it to further process exported files, or generate new files
|
59
|
+
# based on the translations that have been exported.
|
60
|
+
#
|
61
|
+
# Make sure you always check whether your plugin is active before
|
62
|
+
# processing files; otherwise, opting out won't be possible.
|
63
|
+
def self.after_export(files:, config:)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/i18n-js/schema.rb
CHANGED
@@ -4,14 +4,28 @@ module I18nJS
|
|
4
4
|
class Schema
|
5
5
|
InvalidError = Class.new(StandardError)
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
REQUIRED_CHECK_KEYS = %i[ignore].freeze
|
7
|
+
REQUIRED_LINT_TRANSLATIONS_KEYS = %i[ignore].freeze
|
8
|
+
REQUIRED_LINT_SCRIPTS_KEYS = %i[ignore patterns].freeze
|
10
9
|
REQUIRED_TRANSLATION_KEYS = %i[file patterns].freeze
|
11
10
|
TRANSLATION_KEYS = %i[file patterns].freeze
|
12
11
|
|
12
|
+
def self.root_keys
|
13
|
+
@root_keys ||= Set.new(%i[
|
14
|
+
translations
|
15
|
+
lint_translations
|
16
|
+
lint_scripts
|
17
|
+
check
|
18
|
+
])
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.required_root_keys
|
22
|
+
@required_root_keys ||= Set.new(%i[translations])
|
23
|
+
end
|
24
|
+
|
13
25
|
def self.validate!(target)
|
14
|
-
new(target)
|
26
|
+
schema = new(target)
|
27
|
+
schema.validate!
|
28
|
+
I18nJS.plugins.each {|plugin| plugin.validate_schema(config: target) }
|
15
29
|
end
|
16
30
|
|
17
31
|
attr_reader :target
|
@@ -23,20 +37,36 @@ module I18nJS
|
|
23
37
|
def validate!
|
24
38
|
expect_type(:root, target, Hash, target)
|
25
39
|
|
26
|
-
expect_required_keys(
|
27
|
-
reject_extraneous_keys(
|
40
|
+
expect_required_keys(self.class.required_root_keys, target)
|
41
|
+
reject_extraneous_keys(self.class.root_keys, target)
|
28
42
|
validate_translations
|
29
|
-
|
43
|
+
validate_lint_translations
|
44
|
+
validate_lint_scripts
|
30
45
|
end
|
31
46
|
|
32
|
-
def
|
33
|
-
|
47
|
+
def validate_lint_translations
|
48
|
+
key = :lint_translations
|
34
49
|
|
35
|
-
|
50
|
+
return unless target.key?(key)
|
36
51
|
|
37
|
-
|
38
|
-
|
39
|
-
expect_type(
|
52
|
+
config = target[key]
|
53
|
+
|
54
|
+
expect_type(key, config, Hash, target)
|
55
|
+
expect_required_keys(REQUIRED_LINT_TRANSLATIONS_KEYS, config)
|
56
|
+
expect_type(:ignore, config[:ignore], Array, config)
|
57
|
+
end
|
58
|
+
|
59
|
+
def validate_lint_scripts
|
60
|
+
key = :lint_scripts
|
61
|
+
|
62
|
+
return unless target.key?(key)
|
63
|
+
|
64
|
+
config = target[key]
|
65
|
+
|
66
|
+
expect_type(key, config, Hash, target)
|
67
|
+
expect_required_keys(REQUIRED_LINT_SCRIPTS_KEYS, config)
|
68
|
+
expect_type(:ignore, config[:ignore], Array, config)
|
69
|
+
expect_type(:patterns, config[:patterns], Array, config)
|
40
70
|
end
|
41
71
|
|
42
72
|
def validate_translations
|
@@ -63,6 +93,15 @@ module I18nJS
|
|
63
93
|
raise InvalidError, "#{error_message}#{node_json}"
|
64
94
|
end
|
65
95
|
|
96
|
+
def expect_enabled_config(config_key, value)
|
97
|
+
return if [TrueClass, FalseClass].include?(value.class)
|
98
|
+
|
99
|
+
actual_type = value.class
|
100
|
+
|
101
|
+
reject "Expected #{config_key}.enabled to be a boolean; " \
|
102
|
+
"got #{actual_type} instead"
|
103
|
+
end
|
104
|
+
|
66
105
|
def expect_type(attribute, value, expected_type, payload)
|
67
106
|
return if value.is_a?(expected_type)
|
68
107
|
|
@@ -94,7 +133,7 @@ module I18nJS
|
|
94
133
|
|
95
134
|
def reject_extraneous_keys(allowed_keys, value)
|
96
135
|
keys = value.keys.map(&:to_sym)
|
97
|
-
extraneous = keys - allowed_keys
|
136
|
+
extraneous = keys.to_a - allowed_keys.to_a
|
98
137
|
|
99
138
|
return if extraneous.empty?
|
100
139
|
|
data/lib/i18n-js/version.rb
CHANGED
data/lib/i18n-js.rb
CHANGED
@@ -6,9 +6,13 @@ require "yaml"
|
|
6
6
|
require "glob"
|
7
7
|
require "fileutils"
|
8
8
|
require "optparse"
|
9
|
+
require "erb"
|
10
|
+
require "set"
|
11
|
+
require "digest/md5"
|
9
12
|
|
10
13
|
require_relative "i18n-js/schema"
|
11
14
|
require_relative "i18n-js/version"
|
15
|
+
require_relative "i18n-js/plugin"
|
12
16
|
|
13
17
|
module I18nJS
|
14
18
|
MissingConfigError = Class.new(StandardError)
|
@@ -19,19 +23,31 @@ module I18nJS
|
|
19
23
|
"you must set either `config_file` or `config`"
|
20
24
|
end
|
21
25
|
|
22
|
-
|
26
|
+
load_plugins!
|
27
|
+
|
28
|
+
config = Glob::SymbolizeKeys.call(config || load_config_file(config_file))
|
29
|
+
|
23
30
|
Schema.validate!(config)
|
24
31
|
exported_files = []
|
25
32
|
|
26
33
|
config[:translations].each do |group|
|
27
|
-
exported_files += export_group(group)
|
34
|
+
exported_files += export_group(group, config)
|
35
|
+
end
|
36
|
+
|
37
|
+
plugins.each do |plugin|
|
38
|
+
plugin.after_export(files: exported_files.dup, config: config)
|
28
39
|
end
|
29
40
|
|
30
41
|
exported_files
|
31
42
|
end
|
32
43
|
|
33
|
-
def self.export_group(group)
|
44
|
+
def self.export_group(group, config)
|
34
45
|
filtered_translations = Glob.filter(translations, group[:patterns])
|
46
|
+
filtered_translations =
|
47
|
+
plugins.reduce(filtered_translations) do |buffer, plugin|
|
48
|
+
plugin.transform(translations: buffer, config: config)
|
49
|
+
end
|
50
|
+
|
35
51
|
output_file_path = File.expand_path(group[:file])
|
36
52
|
exported_files = []
|
37
53
|
|
@@ -70,4 +86,9 @@ module I18nJS
|
|
70
86
|
translations
|
71
87
|
end
|
72
88
|
end
|
89
|
+
|
90
|
+
def self.load_config_file(config_file)
|
91
|
+
erb = ERB.new(File.read(config_file))
|
92
|
+
YAML.safe_load(erb.result(binding))
|
93
|
+
end
|
73
94
|
end
|
data/package.json
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: i18n-js
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nando Vieira
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: glob
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.4.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.4.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: i18n
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: mocha
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: pry-meta
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -176,6 +190,7 @@ files:
|
|
176
190
|
- MIGRATING_FROM_V3_TO_V4.md
|
177
191
|
- README.md
|
178
192
|
- Rakefile
|
193
|
+
- bin/release
|
179
194
|
- exe/i18n
|
180
195
|
- i18n-js.gemspec
|
181
196
|
- lib/guard/i18n-js.rb
|
@@ -187,11 +202,20 @@ files:
|
|
187
202
|
- lib/i18n-js/cli/command.rb
|
188
203
|
- lib/i18n-js/cli/export_command.rb
|
189
204
|
- lib/i18n-js/cli/init_command.rb
|
205
|
+
- lib/i18n-js/cli/lint_scripts_command.rb
|
206
|
+
- lib/i18n-js/cli/lint_translations_command.rb
|
207
|
+
- lib/i18n-js/cli/plugins_command.rb
|
190
208
|
- lib/i18n-js/cli/ui.rb
|
191
209
|
- lib/i18n-js/cli/version_command.rb
|
210
|
+
- lib/i18n-js/embed_fallback_translations_plugin.rb
|
211
|
+
- lib/i18n-js/export_files_plugin.rb
|
212
|
+
- lib/i18n-js/lint.js
|
213
|
+
- lib/i18n-js/lint.ts
|
192
214
|
- lib/i18n-js/listen.rb
|
215
|
+
- lib/i18n-js/plugin.rb
|
193
216
|
- lib/i18n-js/schema.rb
|
194
217
|
- lib/i18n-js/version.rb
|
218
|
+
- package.json
|
195
219
|
homepage: https://github.com/fnando/i18n-js
|
196
220
|
licenses:
|
197
221
|
- MIT
|
@@ -199,10 +223,10 @@ metadata:
|
|
199
223
|
rubygems_mfa_required: 'true'
|
200
224
|
homepage_uri: https://github.com/fnando/i18n-js
|
201
225
|
bug_tracker_uri: https://github.com/fnando/i18n-js/issues
|
202
|
-
source_code_uri: https://github.com/fnando/i18n-js/tree/v4.0
|
203
|
-
changelog_uri: https://github.com/fnando/i18n-js/tree/v4.0
|
204
|
-
documentation_uri: https://github.com/fnando/i18n-js/tree/v4.0
|
205
|
-
license_uri: https://github.com/fnando/i18n-js/tree/v4.0
|
226
|
+
source_code_uri: https://github.com/fnando/i18n-js/tree/v4.2.0
|
227
|
+
changelog_uri: https://github.com/fnando/i18n-js/tree/v4.2.0/CHANGELOG.md
|
228
|
+
documentation_uri: https://github.com/fnando/i18n-js/tree/v4.2.0/README.md
|
229
|
+
license_uri: https://github.com/fnando/i18n-js/tree/v4.2.0/LICENSE.md
|
206
230
|
post_install_message:
|
207
231
|
rdoc_options: []
|
208
232
|
require_paths:
|
@@ -218,7 +242,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
218
242
|
- !ruby/object:Gem::Version
|
219
243
|
version: '0'
|
220
244
|
requirements: []
|
221
|
-
rubygems_version: 3.3.
|
245
|
+
rubygems_version: 3.3.26
|
222
246
|
signing_key:
|
223
247
|
specification_version: 4
|
224
248
|
summary: Export i18n translations and use them on JavaScript.
|