glotfile 0.5.1 → 0.5.2
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.
- package/dist/server/cli.js +296 -45
- package/dist/server/server.js +252 -42
- package/dist/ui/assets/{index-DC89onXX.js → index-B1UwtMSs.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/package.json +3 -2
- package/skill/SKILL.md +66 -0
- package/skill/references/cli-reference.md +84 -0
- package/skill/references/conventions.md +50 -0
- package/skill/references/schema.md +99 -0
- package/skill/references/workflows.md +84 -0
package/dist/server/server.js
CHANGED
|
@@ -29,7 +29,7 @@ var init_dictionary_en = __esm({
|
|
|
29
29
|
import { Hono as Hono2 } from "hono";
|
|
30
30
|
import { serve } from "@hono/node-server";
|
|
31
31
|
import { fileURLToPath } from "url";
|
|
32
|
-
import { dirname as dirname4, join as
|
|
32
|
+
import { dirname as dirname4, join as join10, resolve as resolve10, extname as extname3, sep as sep3 } from "path";
|
|
33
33
|
import { readFile, stat } from "fs/promises";
|
|
34
34
|
import { createServer } from "net";
|
|
35
35
|
import open from "open";
|
|
@@ -916,7 +916,11 @@ var PATTERNS = {
|
|
|
916
916
|
apple: [
|
|
917
917
|
/NSLocalizedString\s*\(\s*@?"([^"]+)"/g,
|
|
918
918
|
/String\s*\(\s*localized:\s*"([^"]+)"/g,
|
|
919
|
-
/localizedString\s*\(\s*forKey:\s*"([^"]+)"/g
|
|
919
|
+
/localizedString\s*\(\s*forKey:\s*"([^"]+)"/g,
|
|
920
|
+
// The "key".localized / "key".localised String-extension idiom, where the
|
|
921
|
+
// literal IS the key (common when keys are natural-language source text).
|
|
922
|
+
/"([^"]+)"\s*\.\s*localized\b/g,
|
|
923
|
+
/"([^"]+)"\s*\.\s*localised\b/g
|
|
920
924
|
]
|
|
921
925
|
};
|
|
922
926
|
var PREFIX_PATTERNS = {
|
|
@@ -934,7 +938,7 @@ var PREFIX_PATTERNS = {
|
|
|
934
938
|
/(?<!\.)(?<![a-zA-Z0-9_$])\bt\s*\(\s*`([^`$]*)\$\{/g
|
|
935
939
|
]
|
|
936
940
|
};
|
|
937
|
-
var CACHE_VERSION =
|
|
941
|
+
var CACHE_VERSION = 5;
|
|
938
942
|
var EXT_SCANNER = {
|
|
939
943
|
".php": "laravel",
|
|
940
944
|
".vue": "js-i18n",
|
|
@@ -2737,8 +2741,50 @@ var appleStringsdict = {
|
|
|
2737
2741
|
}
|
|
2738
2742
|
};
|
|
2739
2743
|
|
|
2744
|
+
// src/server/adapters/apple-strings.ts
|
|
2745
|
+
var DEFAULT_LOCALE_CASE6 = "bcp47-hyphen";
|
|
2746
|
+
function escape(s) {
|
|
2747
|
+
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\t/g, "\\t").replace(/\r/g, "\\r");
|
|
2748
|
+
}
|
|
2749
|
+
var appleStrings = {
|
|
2750
|
+
name: "apple-strings",
|
|
2751
|
+
capabilities: {
|
|
2752
|
+
// Plurals belong in .stringsdict (apple-stringsdict), not the scalar table.
|
|
2753
|
+
plural: "none",
|
|
2754
|
+
select: "none",
|
|
2755
|
+
nesting: "flat",
|
|
2756
|
+
metadata: false,
|
|
2757
|
+
placeholderStyle: "printf",
|
|
2758
|
+
fileGrouping: "per-locale"
|
|
2759
|
+
},
|
|
2760
|
+
defaultLocaleCase: DEFAULT_LOCALE_CASE6,
|
|
2761
|
+
export(state, output) {
|
|
2762
|
+
const files = [];
|
|
2763
|
+
const warnings = [];
|
|
2764
|
+
warnings.push(...localeCollisionWarnings(output, state.config.locales, DEFAULT_LOCALE_CASE6));
|
|
2765
|
+
const emptyAs = resolveEmptyAs(output, "source");
|
|
2766
|
+
const keys = Object.keys(state.keys).sort();
|
|
2767
|
+
for (const locale of state.config.locales) {
|
|
2768
|
+
const lines = [];
|
|
2769
|
+
for (const key of keys) {
|
|
2770
|
+
const entry = state.keys[key];
|
|
2771
|
+
if (entry.plural) continue;
|
|
2772
|
+
const value = resolveScalar(entry, locale, state.config.sourceLocale, emptyAs);
|
|
2773
|
+
if (value === null) continue;
|
|
2774
|
+
lines.push(`"${escape(key)}" = "${escape(value)}";`);
|
|
2775
|
+
}
|
|
2776
|
+
const contents = lines.length ? lines.join("\n") + "\n" : "";
|
|
2777
|
+
files.push({
|
|
2778
|
+
path: resolvePath(output.path, resolveLocaleToken(output, locale, DEFAULT_LOCALE_CASE6)),
|
|
2779
|
+
contents
|
|
2780
|
+
});
|
|
2781
|
+
}
|
|
2782
|
+
return { files, warnings };
|
|
2783
|
+
}
|
|
2784
|
+
};
|
|
2785
|
+
|
|
2740
2786
|
// src/server/adapters/vue-i18n-json.ts
|
|
2741
|
-
var
|
|
2787
|
+
var DEFAULT_LOCALE_CASE7 = "lower-hyphen";
|
|
2742
2788
|
var vueI18nJson = {
|
|
2743
2789
|
name: "vue-i18n-json",
|
|
2744
2790
|
capabilities: {
|
|
@@ -2749,11 +2795,11 @@ var vueI18nJson = {
|
|
|
2749
2795
|
placeholderStyle: "named",
|
|
2750
2796
|
fileGrouping: "per-locale"
|
|
2751
2797
|
},
|
|
2752
|
-
defaultLocaleCase:
|
|
2798
|
+
defaultLocaleCase: DEFAULT_LOCALE_CASE7,
|
|
2753
2799
|
export(state, output) {
|
|
2754
2800
|
const files = [];
|
|
2755
2801
|
const warnings = [];
|
|
2756
|
-
warnings.push(...localeCollisionWarnings(output, state.config.locales,
|
|
2802
|
+
warnings.push(...localeCollisionWarnings(output, state.config.locales, DEFAULT_LOCALE_CASE7));
|
|
2757
2803
|
const { indent, finalNewline } = resolveFormat(state, output);
|
|
2758
2804
|
const fmt = { indent, sortKeys: true, finalNewline };
|
|
2759
2805
|
const emptyAs = resolveEmptyAs(output, "omit");
|
|
@@ -2793,7 +2839,7 @@ var vueI18nJson = {
|
|
|
2793
2839
|
}
|
|
2794
2840
|
payload = tree;
|
|
2795
2841
|
}
|
|
2796
|
-
files.push({ path: resolvePath(output.path, resolveLocaleToken(output, locale,
|
|
2842
|
+
files.push({ path: resolvePath(output.path, resolveLocaleToken(output, locale, DEFAULT_LOCALE_CASE7)), contents: serializeJson(payload, fmt) });
|
|
2797
2843
|
}
|
|
2798
2844
|
files.sort((a, b) => a.path.localeCompare(b.path));
|
|
2799
2845
|
return { files, warnings };
|
|
@@ -2837,7 +2883,7 @@ function renderEmbeddedIcu(value) {
|
|
|
2837
2883
|
function renderScalar(value, ids) {
|
|
2838
2884
|
return isIcuPluralOrSelect(value) ? renderEmbeddedIcu(value) : renderInterpolations(value, ids);
|
|
2839
2885
|
}
|
|
2840
|
-
var
|
|
2886
|
+
var DEFAULT_LOCALE_CASE8 = "bcp47-hyphen";
|
|
2841
2887
|
var angularXliff = {
|
|
2842
2888
|
name: "angular-xliff",
|
|
2843
2889
|
capabilities: {
|
|
@@ -2848,17 +2894,17 @@ var angularXliff = {
|
|
|
2848
2894
|
placeholderStyle: "icu",
|
|
2849
2895
|
fileGrouping: "per-locale"
|
|
2850
2896
|
},
|
|
2851
|
-
defaultLocaleCase:
|
|
2897
|
+
defaultLocaleCase: DEFAULT_LOCALE_CASE8,
|
|
2852
2898
|
export(state, output) {
|
|
2853
2899
|
const files = [];
|
|
2854
2900
|
const warnings = [];
|
|
2855
|
-
warnings.push(...localeCollisionWarnings(output, state.config.locales,
|
|
2901
|
+
warnings.push(...localeCollisionWarnings(output, state.config.locales, DEFAULT_LOCALE_CASE8));
|
|
2856
2902
|
const sourceLocale = state.config.sourceLocale;
|
|
2857
|
-
const sourceToken = resolveLocaleToken(output, sourceLocale,
|
|
2903
|
+
const sourceToken = resolveLocaleToken(output, sourceLocale, DEFAULT_LOCALE_CASE8);
|
|
2858
2904
|
const emptyAs = resolveEmptyAs(output, "source");
|
|
2859
2905
|
const keys = Object.keys(state.keys).sort();
|
|
2860
2906
|
for (const locale of state.config.locales) {
|
|
2861
|
-
const token = resolveLocaleToken(output, locale,
|
|
2907
|
+
const token = resolveLocaleToken(output, locale, DEFAULT_LOCALE_CASE8);
|
|
2862
2908
|
const units = [];
|
|
2863
2909
|
for (const key of keys) {
|
|
2864
2910
|
const entry = state.keys[key];
|
|
@@ -2921,7 +2967,7 @@ function yamlMap(node, indent, level) {
|
|
|
2921
2967
|
}
|
|
2922
2968
|
return lines;
|
|
2923
2969
|
}
|
|
2924
|
-
var
|
|
2970
|
+
var DEFAULT_LOCALE_CASE9 = "bcp47-hyphen";
|
|
2925
2971
|
var railsYaml = {
|
|
2926
2972
|
name: "rails-yaml",
|
|
2927
2973
|
capabilities: {
|
|
@@ -2932,10 +2978,10 @@ var railsYaml = {
|
|
|
2932
2978
|
placeholderStyle: "named",
|
|
2933
2979
|
fileGrouping: "per-locale"
|
|
2934
2980
|
},
|
|
2935
|
-
defaultLocaleCase:
|
|
2981
|
+
defaultLocaleCase: DEFAULT_LOCALE_CASE9,
|
|
2936
2982
|
export(state, output) {
|
|
2937
2983
|
const warnings = [];
|
|
2938
|
-
warnings.push(...localeCollisionWarnings(output, state.config.locales,
|
|
2984
|
+
warnings.push(...localeCollisionWarnings(output, state.config.locales, DEFAULT_LOCALE_CASE9));
|
|
2939
2985
|
const { indent, finalNewline } = resolveFormat(state, output);
|
|
2940
2986
|
const emptyAs = resolveEmptyAs(output, "omit");
|
|
2941
2987
|
const files = [];
|
|
@@ -2967,7 +3013,7 @@ var railsYaml = {
|
|
|
2967
3013
|
for (const c of collisions) {
|
|
2968
3014
|
warnings.push({ code: "key-collision", key: c, locale, message: "key is both a leaf and a parent; dropped from nested output" });
|
|
2969
3015
|
}
|
|
2970
|
-
const token = resolveLocaleToken(output, locale,
|
|
3016
|
+
const token = resolveLocaleToken(output, locale, DEFAULT_LOCALE_CASE9);
|
|
2971
3017
|
const body = [`${yamlKey(token)}:`, ...yamlMap(nested, indent, 1)].join("\n");
|
|
2972
3018
|
files.push({ path: resolvePath(output.path, token), contents: finalNewline ? body + "\n" : body });
|
|
2973
3019
|
}
|
|
@@ -3008,6 +3054,7 @@ function getRegistry() {
|
|
|
3008
3054
|
[i18nextJson.name]: i18nextJson,
|
|
3009
3055
|
[gettextPo.name]: gettextPo,
|
|
3010
3056
|
[appleStringsdict.name]: appleStringsdict,
|
|
3057
|
+
[appleStrings.name]: appleStrings,
|
|
3011
3058
|
[vueI18nJson.name]: vueI18nJson,
|
|
3012
3059
|
[angularXliff.name]: angularXliff,
|
|
3013
3060
|
[railsYaml.name]: railsYaml
|
|
@@ -3038,8 +3085,8 @@ function checkOutputs(state, root) {
|
|
|
3038
3085
|
}
|
|
3039
3086
|
|
|
3040
3087
|
// src/server/api.ts
|
|
3041
|
-
import { readFileSync as
|
|
3042
|
-
import { dirname as dirname3, resolve as resolve9, basename, relative as
|
|
3088
|
+
import { readFileSync as readFileSync15, existsSync as existsSync11, readdirSync as readdirSync9, statSync as statSync6, rmSync as rmSync4 } from "fs";
|
|
3089
|
+
import { dirname as dirname3, resolve as resolve9, basename, relative as relative4, sep as sep2 } from "path";
|
|
3043
3090
|
|
|
3044
3091
|
// src/server/ai/anthropic.ts
|
|
3045
3092
|
import Anthropic from "@anthropic-ai/sdk";
|
|
@@ -3685,6 +3732,9 @@ function readLog(projectRoot, limit = 100) {
|
|
|
3685
3732
|
return entries.reverse().slice(0, limit);
|
|
3686
3733
|
}
|
|
3687
3734
|
|
|
3735
|
+
// src/server/import/run.ts
|
|
3736
|
+
import { relative as relative3 } from "path";
|
|
3737
|
+
|
|
3688
3738
|
// src/server/import/detect.ts
|
|
3689
3739
|
import { existsSync as existsSync9, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
|
|
3690
3740
|
import { join as join4 } from "path";
|
|
@@ -3749,11 +3799,38 @@ function detectArb(root) {
|
|
|
3749
3799
|
}
|
|
3750
3800
|
return null;
|
|
3751
3801
|
}
|
|
3752
|
-
|
|
3802
|
+
function lprojLocales(dir) {
|
|
3803
|
+
return listDirs(dir).map((d) => d.match(/^(.+)\.lproj$/)?.[1]).filter((l) => !!l && LOCALE_RE.test(l) && existsSync9(join4(dir, `${l}.lproj`, "Localizable.strings")));
|
|
3804
|
+
}
|
|
3805
|
+
function detectApple(root) {
|
|
3806
|
+
const candidates = [root, ...listDirs(root).map((d) => join4(root, d))];
|
|
3807
|
+
let best = null;
|
|
3808
|
+
for (const dir of candidates) {
|
|
3809
|
+
const locales = lprojLocales(dir);
|
|
3810
|
+
if (locales.length === 0) continue;
|
|
3811
|
+
if (!best || locales.length > best.locales.length) {
|
|
3812
|
+
best = {
|
|
3813
|
+
format: "apple-strings",
|
|
3814
|
+
localeRoot: dir,
|
|
3815
|
+
locales,
|
|
3816
|
+
sourceLocale: pickSource(locales, (loc) => {
|
|
3817
|
+
try {
|
|
3818
|
+
return statSync2(join4(dir, `${loc}.lproj`, "Localizable.strings")).size;
|
|
3819
|
+
} catch {
|
|
3820
|
+
return 0;
|
|
3821
|
+
}
|
|
3822
|
+
})
|
|
3823
|
+
};
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
return best;
|
|
3827
|
+
}
|
|
3828
|
+
var DETECTORS = [detectLaravel, detectVue, detectArb, detectApple];
|
|
3753
3829
|
var BY_FORMAT = {
|
|
3754
3830
|
"laravel-php": detectLaravel,
|
|
3755
3831
|
"vue-i18n-json": (root) => detectVue(root, true),
|
|
3756
|
-
"flutter-arb": detectArb
|
|
3832
|
+
"flutter-arb": detectArb,
|
|
3833
|
+
"apple-strings": detectApple
|
|
3757
3834
|
};
|
|
3758
3835
|
function detect(root, formatOverride) {
|
|
3759
3836
|
if (!existsSync9(root)) return null;
|
|
@@ -3963,11 +4040,139 @@ var flutterArb2 = {
|
|
|
3963
4040
|
}
|
|
3964
4041
|
};
|
|
3965
4042
|
|
|
4043
|
+
// src/server/import/parsers/apple-strings.ts
|
|
4044
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync11, statSync as statSync4 } from "fs";
|
|
4045
|
+
import { join as join8 } from "path";
|
|
4046
|
+
var LOCALE_RE4 = /^[a-z]{2,3}([_-][A-Za-z]{2,4}){0,2}$/;
|
|
4047
|
+
var TABLE = "Localizable.strings";
|
|
4048
|
+
function localeFromLproj(dir) {
|
|
4049
|
+
const m = dir.match(/^(.+)\.lproj$/);
|
|
4050
|
+
if (!m) return null;
|
|
4051
|
+
return LOCALE_RE4.test(m[1]) ? m[1] : null;
|
|
4052
|
+
}
|
|
4053
|
+
function unescape(body) {
|
|
4054
|
+
return body.replace(/\\(U[0-9a-fA-F]{4}|u[0-9a-fA-F]{4}|.)/g, (_m, esc) => {
|
|
4055
|
+
const c = esc[0];
|
|
4056
|
+
if (c === "U" || c === "u") return String.fromCharCode(parseInt(esc.slice(1), 16));
|
|
4057
|
+
if (c === "n") return "\n";
|
|
4058
|
+
if (c === "t") return " ";
|
|
4059
|
+
if (c === "r") return "\r";
|
|
4060
|
+
return esc;
|
|
4061
|
+
});
|
|
4062
|
+
}
|
|
4063
|
+
function parseStrings(text, file, warnings) {
|
|
4064
|
+
const pairs = [];
|
|
4065
|
+
let i = 0;
|
|
4066
|
+
const n = text.length;
|
|
4067
|
+
const skipTrivia = () => {
|
|
4068
|
+
while (i < n) {
|
|
4069
|
+
const c = text[i];
|
|
4070
|
+
if (c === " " || c === " " || c === "\n" || c === "\r") {
|
|
4071
|
+
i++;
|
|
4072
|
+
continue;
|
|
4073
|
+
}
|
|
4074
|
+
if (c === "/" && text[i + 1] === "/") {
|
|
4075
|
+
i += 2;
|
|
4076
|
+
while (i < n && text[i] !== "\n") i++;
|
|
4077
|
+
continue;
|
|
4078
|
+
}
|
|
4079
|
+
if (c === "/" && text[i + 1] === "*") {
|
|
4080
|
+
i += 2;
|
|
4081
|
+
while (i < n && !(text[i] === "*" && text[i + 1] === "/")) i++;
|
|
4082
|
+
i += 2;
|
|
4083
|
+
continue;
|
|
4084
|
+
}
|
|
4085
|
+
break;
|
|
4086
|
+
}
|
|
4087
|
+
};
|
|
4088
|
+
const readToken = () => {
|
|
4089
|
+
if (i >= n) return null;
|
|
4090
|
+
if (text[i] === '"') {
|
|
4091
|
+
i++;
|
|
4092
|
+
let raw2 = "";
|
|
4093
|
+
while (i < n) {
|
|
4094
|
+
const c = text[i];
|
|
4095
|
+
if (c === "\\") {
|
|
4096
|
+
raw2 += c + (text[i + 1] ?? "");
|
|
4097
|
+
i += 2;
|
|
4098
|
+
continue;
|
|
4099
|
+
}
|
|
4100
|
+
if (c === '"') {
|
|
4101
|
+
i++;
|
|
4102
|
+
return unescape(raw2);
|
|
4103
|
+
}
|
|
4104
|
+
raw2 += c;
|
|
4105
|
+
i++;
|
|
4106
|
+
}
|
|
4107
|
+
return null;
|
|
4108
|
+
}
|
|
4109
|
+
let raw = "";
|
|
4110
|
+
while (i < n && !/[\s=;]/.test(text[i])) raw += text[i++];
|
|
4111
|
+
return raw.length ? raw : null;
|
|
4112
|
+
};
|
|
4113
|
+
while (true) {
|
|
4114
|
+
skipTrivia();
|
|
4115
|
+
if (i >= n) break;
|
|
4116
|
+
const key = readToken();
|
|
4117
|
+
if (key === null) {
|
|
4118
|
+
warnings.push(`apple-strings: malformed entry in ${file} near offset ${i}`);
|
|
4119
|
+
break;
|
|
4120
|
+
}
|
|
4121
|
+
skipTrivia();
|
|
4122
|
+
if (text[i] !== "=") {
|
|
4123
|
+
warnings.push(`apple-strings: expected '=' after key "${key}" in ${file}`);
|
|
4124
|
+
break;
|
|
4125
|
+
}
|
|
4126
|
+
i++;
|
|
4127
|
+
skipTrivia();
|
|
4128
|
+
const value = readToken();
|
|
4129
|
+
if (value === null) {
|
|
4130
|
+
warnings.push(`apple-strings: missing value for key "${key}" in ${file}`);
|
|
4131
|
+
break;
|
|
4132
|
+
}
|
|
4133
|
+
skipTrivia();
|
|
4134
|
+
if (text[i] === ";") i++;
|
|
4135
|
+
pairs.push({ key, value });
|
|
4136
|
+
}
|
|
4137
|
+
return pairs;
|
|
4138
|
+
}
|
|
4139
|
+
var appleStrings2 = {
|
|
4140
|
+
name: "apple-strings",
|
|
4141
|
+
parse(localeRoot, opts) {
|
|
4142
|
+
const warnings = [];
|
|
4143
|
+
const keys = {};
|
|
4144
|
+
const locales = [];
|
|
4145
|
+
for (const dir of readdirSync7(localeRoot).sort()) {
|
|
4146
|
+
const locale = localeFromLproj(dir);
|
|
4147
|
+
if (!locale) continue;
|
|
4148
|
+
if (opts?.locales && !opts.locales.includes(locale)) continue;
|
|
4149
|
+
const file = join8(localeRoot, dir, TABLE);
|
|
4150
|
+
let text;
|
|
4151
|
+
try {
|
|
4152
|
+
if (!statSync4(file).isFile()) continue;
|
|
4153
|
+
text = readFileSync11(file, "utf8");
|
|
4154
|
+
} catch {
|
|
4155
|
+
continue;
|
|
4156
|
+
}
|
|
4157
|
+
locales.push(locale);
|
|
4158
|
+
const others = readdirSync7(join8(localeRoot, dir)).filter((f) => f.endsWith(".strings") && f !== TABLE);
|
|
4159
|
+
if (others.length) {
|
|
4160
|
+
warnings.push(`apple-strings: ${dir} has other .strings tables (${others.join(", ")}); only ${TABLE} is imported`);
|
|
4161
|
+
}
|
|
4162
|
+
for (const { key, value } of parseStrings(text, file, warnings)) {
|
|
4163
|
+
(keys[key] ??= { values: {} }).values[locale] = value;
|
|
4164
|
+
}
|
|
4165
|
+
}
|
|
4166
|
+
return { locales, keys, warnings };
|
|
4167
|
+
}
|
|
4168
|
+
};
|
|
4169
|
+
|
|
3966
4170
|
// src/server/import/parsers/index.ts
|
|
3967
4171
|
var REGISTRY = {
|
|
3968
4172
|
[vueI18nJson2.name]: vueI18nJson2,
|
|
3969
4173
|
[laravelPhp2.name]: laravelPhp2,
|
|
3970
|
-
[flutterArb2.name]: flutterArb2
|
|
4174
|
+
[flutterArb2.name]: flutterArb2,
|
|
4175
|
+
[appleStrings2.name]: appleStrings2
|
|
3971
4176
|
};
|
|
3972
4177
|
function getParser(name) {
|
|
3973
4178
|
const p = REGISTRY[name];
|
|
@@ -3979,16 +4184,20 @@ function getParser(name) {
|
|
|
3979
4184
|
var OUTPUT_BY_FORMAT = {
|
|
3980
4185
|
"laravel-php": { adapter: "laravel-php", path: "lang/{locale}/{namespace}.php" },
|
|
3981
4186
|
"vue-i18n-json": { adapter: "vue-i18n-json", path: "src/locale/{locale}.json" },
|
|
3982
|
-
"flutter-arb": { adapter: "flutter-arb", path: "lib/l10n/app_{locale}.arb" }
|
|
4187
|
+
"flutter-arb": { adapter: "flutter-arb", path: "lib/l10n/app_{locale}.arb" },
|
|
4188
|
+
"apple-strings": { adapter: "apple-strings", path: "{locale}.lproj/Localizable.strings", rootRelative: true }
|
|
3983
4189
|
};
|
|
3984
4190
|
function assemble2(parsed, opts) {
|
|
3985
4191
|
const warnings = [...parsed.warnings];
|
|
3986
4192
|
const base = OUTPUT_BY_FORMAT[opts.format];
|
|
3987
4193
|
if (!base) throw new Error(`No output mapping for format "${opts.format}"`);
|
|
4194
|
+
const prefix = (opts.localeRootRel ?? "").replace(/\\/g, "/").replace(/\/+$/, "");
|
|
4195
|
+
const path = base.rootRelative && prefix ? `${prefix}/${base.path}` : base.path;
|
|
3988
4196
|
const rawLocales = [.../* @__PURE__ */ new Set([opts.sourceLocale, ...parsed.locales])];
|
|
3989
4197
|
const pairs = rawLocales.map((obs) => [canonLocale(obs), obs]);
|
|
3990
4198
|
const inferred = inferLocaleStyle(pairs, getAdapter(base.adapter).defaultLocaleCase);
|
|
3991
|
-
const
|
|
4199
|
+
const { rootRelative: _rootRelative, ...baseOutput } = base;
|
|
4200
|
+
const output = { ...baseOutput, path, ...inferred };
|
|
3992
4201
|
const sourceLocale = canonLocale(opts.sourceLocale);
|
|
3993
4202
|
const locales = [...new Set(rawLocales.map(canonLocale))].sort();
|
|
3994
4203
|
const keys = {};
|
|
@@ -4080,7 +4289,8 @@ function runImport(opts) {
|
|
|
4080
4289
|
const assembled = assemble2(parsed, {
|
|
4081
4290
|
sourceLocale: opts.sourceLocale ?? det.sourceLocale,
|
|
4082
4291
|
format: det.format,
|
|
4083
|
-
cldr: opts.cldr
|
|
4292
|
+
cldr: opts.cldr,
|
|
4293
|
+
localeRootRel: relative3(opts.projectRoot, det.localeRoot)
|
|
4084
4294
|
});
|
|
4085
4295
|
const { warnings, ...rest } = assembled;
|
|
4086
4296
|
const state = validate(rest);
|
|
@@ -4093,7 +4303,7 @@ function runImport(opts) {
|
|
|
4093
4303
|
}
|
|
4094
4304
|
|
|
4095
4305
|
// src/server/export-run.ts
|
|
4096
|
-
import { existsSync as existsSync10, readFileSync as
|
|
4306
|
+
import { existsSync as existsSync10, readFileSync as readFileSync12, readdirSync as readdirSync8, rmdirSync, statSync as statSync5, unlinkSync } from "fs";
|
|
4097
4307
|
import { dirname as dirname2, resolve as resolve7, sep } from "path";
|
|
4098
4308
|
function effectiveLocales(config) {
|
|
4099
4309
|
const limit = config.exportLocales;
|
|
@@ -4136,7 +4346,7 @@ function pruneStaleLocaleFiles(output, validTokens, projectRoot) {
|
|
|
4136
4346
|
if (!segment.includes("{locale}") && !segment.includes("{namespace}")) {
|
|
4137
4347
|
const next = resolve7(dir, segment);
|
|
4138
4348
|
if (isLast) {
|
|
4139
|
-
if (stale(locale) && existsSync10(next) &&
|
|
4349
|
+
if (stale(locale) && existsSync10(next) && statSync5(next).isFile()) {
|
|
4140
4350
|
unlinkSync(next);
|
|
4141
4351
|
deleted++;
|
|
4142
4352
|
removeEmptyDirs(dir, root);
|
|
@@ -4149,7 +4359,7 @@ function pruneStaleLocaleFiles(output, validTokens, projectRoot) {
|
|
|
4149
4359
|
const re = segmentRegExp(segment);
|
|
4150
4360
|
let entries;
|
|
4151
4361
|
try {
|
|
4152
|
-
entries =
|
|
4362
|
+
entries = readdirSync8(dir, { withFileTypes: true });
|
|
4153
4363
|
} catch {
|
|
4154
4364
|
return;
|
|
4155
4365
|
}
|
|
@@ -4192,7 +4402,7 @@ function exportToDisk(state, projectRoot, opts) {
|
|
|
4192
4402
|
writtenPaths.add(abs);
|
|
4193
4403
|
let current = null;
|
|
4194
4404
|
try {
|
|
4195
|
-
current =
|
|
4405
|
+
current = readFileSync12(abs, "utf8");
|
|
4196
4406
|
} catch {
|
|
4197
4407
|
}
|
|
4198
4408
|
if (current === f.contents) {
|
|
@@ -4209,17 +4419,17 @@ function exportToDisk(state, projectRoot, opts) {
|
|
|
4209
4419
|
}
|
|
4210
4420
|
|
|
4211
4421
|
// src/server/ui-prefs.ts
|
|
4212
|
-
import { readFileSync as
|
|
4422
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
4213
4423
|
import { homedir } from "os";
|
|
4214
|
-
import { join as
|
|
4424
|
+
import { join as join9 } from "path";
|
|
4215
4425
|
var THEMES = ["system", "light", "dark"];
|
|
4216
4426
|
var isThemeMode = (v) => THEMES.includes(v);
|
|
4217
4427
|
var isPanelWidth = (v) => typeof v === "number" && Number.isFinite(v) && v >= 120 && v <= 1200;
|
|
4218
|
-
var defaultUiPrefsPath = () =>
|
|
4428
|
+
var defaultUiPrefsPath = () => join9(homedir(), ".glotfile", "ui.json");
|
|
4219
4429
|
var DEFAULTS = { theme: "system" };
|
|
4220
4430
|
function readJson(path) {
|
|
4221
4431
|
try {
|
|
4222
|
-
const parsed = JSON.parse(
|
|
4432
|
+
const parsed = JSON.parse(readFileSync13(path, "utf8"));
|
|
4223
4433
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
4224
4434
|
} catch {
|
|
4225
4435
|
return {};
|
|
@@ -4238,7 +4448,7 @@ function saveUiPrefs(path, prefs) {
|
|
|
4238
4448
|
}
|
|
4239
4449
|
|
|
4240
4450
|
// src/server/local-settings.ts
|
|
4241
|
-
import { readFileSync as
|
|
4451
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
4242
4452
|
import { resolve as resolve8 } from "path";
|
|
4243
4453
|
var EDITOR_IDS = ["vscode", "zed", "phpstorm"];
|
|
4244
4454
|
var isEditorId = (v) => EDITOR_IDS.includes(v);
|
|
@@ -4253,7 +4463,7 @@ var DEFAULT_EDITOR = "vscode";
|
|
|
4253
4463
|
var settingsPath = (projectRoot) => resolve8(projectRoot, ".glotfile", "settings.json");
|
|
4254
4464
|
function readJson2(path) {
|
|
4255
4465
|
try {
|
|
4256
|
-
const parsed = JSON.parse(
|
|
4466
|
+
const parsed = JSON.parse(readFileSync14(path, "utf8"));
|
|
4257
4467
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
4258
4468
|
} catch {
|
|
4259
4469
|
return {};
|
|
@@ -4326,7 +4536,7 @@ function projectName(root) {
|
|
|
4326
4536
|
const nameFile = resolve9(root, ".idea", ".name");
|
|
4327
4537
|
if (existsSync11(nameFile)) {
|
|
4328
4538
|
try {
|
|
4329
|
-
const name =
|
|
4539
|
+
const name = readFileSync15(nameFile, "utf8").trim();
|
|
4330
4540
|
if (name) return name;
|
|
4331
4541
|
} catch {
|
|
4332
4542
|
}
|
|
@@ -4441,7 +4651,7 @@ function createApi(deps) {
|
|
|
4441
4651
|
app.get("/file", (c) => c.json({ path: deps.statePath, name: basename(deps.statePath), dir: projectRoot, project: basename(projectRoot) }));
|
|
4442
4652
|
app.get("/files", (c) => {
|
|
4443
4653
|
const found = /* @__PURE__ */ new Map();
|
|
4444
|
-
const activeRel =
|
|
4654
|
+
const activeRel = relative4(projectRoot, deps.statePath);
|
|
4445
4655
|
found.set(deps.statePath, {
|
|
4446
4656
|
name: basename(deps.statePath),
|
|
4447
4657
|
path: deps.statePath,
|
|
@@ -4451,7 +4661,7 @@ function createApi(deps) {
|
|
|
4451
4661
|
if (depth > 4) return;
|
|
4452
4662
|
let entries = [];
|
|
4453
4663
|
try {
|
|
4454
|
-
entries =
|
|
4664
|
+
entries = readdirSync9(dir);
|
|
4455
4665
|
} catch {
|
|
4456
4666
|
return;
|
|
4457
4667
|
}
|
|
@@ -4465,7 +4675,7 @@ function createApi(deps) {
|
|
|
4465
4675
|
filePath = abs;
|
|
4466
4676
|
} else {
|
|
4467
4677
|
try {
|
|
4468
|
-
if (
|
|
4678
|
+
if (statSync6(abs).isDirectory()) walk(abs, depth + 1);
|
|
4469
4679
|
} catch {
|
|
4470
4680
|
}
|
|
4471
4681
|
continue;
|
|
@@ -4473,7 +4683,7 @@ function createApi(deps) {
|
|
|
4473
4683
|
if (found.has(filePath)) continue;
|
|
4474
4684
|
try {
|
|
4475
4685
|
loadState(filePath);
|
|
4476
|
-
const rel =
|
|
4686
|
+
const rel = relative4(projectRoot, filePath);
|
|
4477
4687
|
found.set(filePath, { name: basename(filePath), path: filePath, relDir: rel !== basename(filePath) ? dirname3(rel) : void 0 });
|
|
4478
4688
|
} catch {
|
|
4479
4689
|
}
|
|
@@ -4552,7 +4762,7 @@ function createApi(deps) {
|
|
|
4552
4762
|
for (const e of Object.values(s.keys)) if (e.screenshot === screenshot) return;
|
|
4553
4763
|
const root = dirname3(resolve9(deps.statePath));
|
|
4554
4764
|
const abs = resolve9(root, screenshot);
|
|
4555
|
-
const rel =
|
|
4765
|
+
const rel = relative4(root, abs);
|
|
4556
4766
|
const seg0 = rel.split(sep2)[0] ?? "";
|
|
4557
4767
|
if (!rel.startsWith("..") && seg0.endsWith("-screenshots") && existsSync11(abs)) {
|
|
4558
4768
|
try {
|
|
@@ -5246,7 +5456,7 @@ function createApi(deps) {
|
|
|
5246
5456
|
|
|
5247
5457
|
// src/server/server.ts
|
|
5248
5458
|
var here = dirname4(fileURLToPath(import.meta.url));
|
|
5249
|
-
var DEFAULT_UI_DIR =
|
|
5459
|
+
var DEFAULT_UI_DIR = join10(here, "..", "ui");
|
|
5250
5460
|
var MIME = {
|
|
5251
5461
|
".html": "text/html; charset=utf-8",
|
|
5252
5462
|
".js": "text/javascript; charset=utf-8",
|
|
@@ -5300,7 +5510,7 @@ function buildApp(opts) {
|
|
|
5300
5510
|
const file = await readFileResponse(target);
|
|
5301
5511
|
if (file) return file;
|
|
5302
5512
|
}
|
|
5303
|
-
const index = await readFileResponse(
|
|
5513
|
+
const index = await readFileResponse(join10(root, "index.html"));
|
|
5304
5514
|
if (index) return index;
|
|
5305
5515
|
return c.notFound();
|
|
5306
5516
|
});
|