i18n-js 4.0.0 → 4.1.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 +20 -1
- data/MIGRATING_FROM_V3_TO_V4.md +191 -0
- data/README.md +267 -25
- data/bin/pack +79 -0
- data/i18n-js.gemspec +5 -2
- data/lib/guard/i18n-js.rb +21 -4
- data/lib/i18n-js/cli/check_command.rb +7 -147
- data/lib/i18n-js/cli/command.rb +10 -0
- data/lib/i18n-js/cli/export_command.rb +17 -3
- 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 +78 -0
- data/lib/i18n-js/lint.js +150645 -0
- data/lib/i18n-js/lint.ts +196 -0
- data/lib/i18n-js/listen.rb +25 -10
- data/lib/i18n-js/plugin.rb +38 -0
- data/lib/i18n-js/schema.rb +53 -14
- data/lib/i18n-js/version.rb +1 -1
- data/lib/i18n-js.rb +20 -3
- data/package.json +10 -0
- metadata +33 -11
- data/i18njs.png +0 -0
- data/images/i18njs-check.gif +0 -0
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
@@ -7,7 +7,9 @@ module I18nJS
|
|
7
7
|
|
8
8
|
def self.listen(
|
9
9
|
config_file: Rails.root.join("config/i18n.yml"),
|
10
|
-
locales_dir: Rails.root.join("config/locales")
|
10
|
+
locales_dir: Rails.root.join("config/locales"),
|
11
|
+
run_on_start: true,
|
12
|
+
options: {}
|
11
13
|
)
|
12
14
|
return unless Rails.env.development?
|
13
15
|
return if started
|
@@ -18,13 +20,15 @@ module I18nJS
|
|
18
20
|
|
19
21
|
self.started = true
|
20
22
|
|
23
|
+
locales_dirs = Array(locales_dir).map {|path| File.expand_path(path) }
|
24
|
+
|
21
25
|
relative_paths =
|
22
|
-
[config_file,
|
26
|
+
[config_file, *locales_dirs].map {|path| relative_path(path) }
|
23
27
|
|
24
28
|
debug("Watching #{relative_paths.inspect}")
|
25
29
|
|
26
|
-
listener(config_file,
|
27
|
-
I18nJS.call(config_file: config_file)
|
30
|
+
listener(config_file, locales_dirs.map(&:to_s), options).start
|
31
|
+
I18nJS.call(config_file: config_file) if run_on_start
|
28
32
|
end
|
29
33
|
|
30
34
|
def self.relative_path(path)
|
@@ -43,12 +47,12 @@ module I18nJS
|
|
43
47
|
@logger ||= ActiveSupport::TaggedLogging.new(Rails.logger)
|
44
48
|
end
|
45
49
|
|
46
|
-
def self.listener(config_file,
|
47
|
-
paths = [File.dirname(config_file),
|
50
|
+
def self.listener(config_file, locales_dirs, options)
|
51
|
+
paths = [File.dirname(config_file), *locales_dirs]
|
48
52
|
|
49
|
-
Listen.to(*paths) do |changed, added, removed|
|
53
|
+
Listen.to(*paths, options) do |changed, added, removed|
|
50
54
|
changes = compute_changes(
|
51
|
-
[config_file,
|
55
|
+
[config_file, *locales_dirs],
|
52
56
|
changed,
|
53
57
|
added,
|
54
58
|
removed
|
@@ -58,11 +62,22 @@ module I18nJS
|
|
58
62
|
|
59
63
|
debug(changes.map {|key, value| "#{key}=#{value.inspect}" }.join(", "))
|
60
64
|
|
61
|
-
|
62
|
-
|
65
|
+
capture do
|
66
|
+
system "i18n", "export", "--config", config_file.to_s
|
67
|
+
end
|
63
68
|
end
|
64
69
|
end
|
65
70
|
|
71
|
+
def self.capture
|
72
|
+
original = $stdout
|
73
|
+
$stdout = StringIO.new
|
74
|
+
yield
|
75
|
+
rescue StandardError
|
76
|
+
# noop
|
77
|
+
ensure
|
78
|
+
$stdout = original
|
79
|
+
end
|
80
|
+
|
66
81
|
def self.compute_changes(paths, changed, added, removed)
|
67
82
|
paths = paths.map {|path| relative_path(path) }
|
68
83
|
|
@@ -0,0 +1,38 @@
|
|
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
|
+
def self.transform(translations:, config:) # rubocop:disable Lint/UnusedMethodArgument
|
27
|
+
translations
|
28
|
+
end
|
29
|
+
|
30
|
+
# Must raise I18nJS::SchemaInvalidError with the error message if schema
|
31
|
+
# validation has failed.
|
32
|
+
def self.validate_schema(config:)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.setup
|
36
|
+
end
|
37
|
+
end
|
38
|
+
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,27 @@ 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)
|
28
35
|
end
|
29
36
|
|
30
37
|
exported_files
|
31
38
|
end
|
32
39
|
|
33
|
-
def self.export_group(group)
|
40
|
+
def self.export_group(group, config)
|
34
41
|
filtered_translations = Glob.filter(translations, group[:patterns])
|
42
|
+
filtered_translations =
|
43
|
+
plugins.reduce(filtered_translations) do |buffer, plugin|
|
44
|
+
plugin.transform(translations: buffer, config: config)
|
45
|
+
end
|
46
|
+
|
35
47
|
output_file_path = File.expand_path(group[:file])
|
36
48
|
exported_files = []
|
37
49
|
|
@@ -70,4 +82,9 @@ module I18nJS
|
|
70
82
|
translations
|
71
83
|
end
|
72
84
|
end
|
85
|
+
|
86
|
+
def self.load_config_file(config_file)
|
87
|
+
erb = ERB.new(File.read(config_file))
|
88
|
+
YAML.safe_load(erb.result(binding))
|
89
|
+
end
|
73
90
|
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.
|
4
|
+
version: 4.1.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-09 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
|
@@ -173,12 +187,12 @@ files:
|
|
173
187
|
- CONTRIBUTING.md
|
174
188
|
- Gemfile
|
175
189
|
- LICENSE.md
|
190
|
+
- MIGRATING_FROM_V3_TO_V4.md
|
176
191
|
- README.md
|
177
192
|
- Rakefile
|
193
|
+
- bin/pack
|
178
194
|
- exe/i18n
|
179
195
|
- i18n-js.gemspec
|
180
|
-
- i18njs.png
|
181
|
-
- images/i18njs-check.gif
|
182
196
|
- lib/guard/i18n-js.rb
|
183
197
|
- lib/guard/i18n-js/templates/Guardfile
|
184
198
|
- lib/guard/i18n-js/version.rb
|
@@ -188,11 +202,19 @@ files:
|
|
188
202
|
- lib/i18n-js/cli/command.rb
|
189
203
|
- lib/i18n-js/cli/export_command.rb
|
190
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
|
191
208
|
- lib/i18n-js/cli/ui.rb
|
192
209
|
- lib/i18n-js/cli/version_command.rb
|
210
|
+
- lib/i18n-js/embed_fallback_translations_plugin.rb
|
211
|
+
- lib/i18n-js/lint.js
|
212
|
+
- lib/i18n-js/lint.ts
|
193
213
|
- lib/i18n-js/listen.rb
|
214
|
+
- lib/i18n-js/plugin.rb
|
194
215
|
- lib/i18n-js/schema.rb
|
195
216
|
- lib/i18n-js/version.rb
|
217
|
+
- package.json
|
196
218
|
homepage: https://github.com/fnando/i18n-js
|
197
219
|
licenses:
|
198
220
|
- MIT
|
@@ -200,10 +222,10 @@ metadata:
|
|
200
222
|
rubygems_mfa_required: 'true'
|
201
223
|
homepage_uri: https://github.com/fnando/i18n-js
|
202
224
|
bug_tracker_uri: https://github.com/fnando/i18n-js/issues
|
203
|
-
source_code_uri: https://github.com/fnando/i18n-js/tree/v4.
|
204
|
-
changelog_uri: https://github.com/fnando/i18n-js/tree/v4.
|
205
|
-
documentation_uri: https://github.com/fnando/i18n-js/tree/v4.
|
206
|
-
license_uri: https://github.com/fnando/i18n-js/tree/v4.
|
225
|
+
source_code_uri: https://github.com/fnando/i18n-js/tree/v4.1.0
|
226
|
+
changelog_uri: https://github.com/fnando/i18n-js/tree/v4.1.0/CHANGELOG.md
|
227
|
+
documentation_uri: https://github.com/fnando/i18n-js/tree/v4.1.0/README.md
|
228
|
+
license_uri: https://github.com/fnando/i18n-js/tree/v4.1.0/LICENSE.md
|
207
229
|
post_install_message:
|
208
230
|
rdoc_options: []
|
209
231
|
require_paths:
|
@@ -219,7 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
219
241
|
- !ruby/object:Gem::Version
|
220
242
|
version: '0'
|
221
243
|
requirements: []
|
222
|
-
rubygems_version: 3.3.
|
244
|
+
rubygems_version: 3.3.26
|
223
245
|
signing_key:
|
224
246
|
specification_version: 4
|
225
247
|
summary: Export i18n translations and use them on JavaScript.
|
data/i18njs.png
DELETED
Binary file
|
data/images/i18njs-check.gif
DELETED
Binary file
|