Skip to content

Commit 1964c64

Browse files
Merge pull request #330 from N1ebieski/Support-for-locale-parameter-in-translations-#21
Support for locale parameter in translations
2 parents c96ece5 + 423311a commit 1964c64

File tree

6 files changed

+175
-14
lines changed

6 files changed

+175
-14
lines changed

php-templates/translations.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
public $directoriesToWatch = [];
1616

17+
public $languages = [];
18+
1719
public function all()
1820
{
1921
$final = [];
@@ -24,13 +26,21 @@ public function all()
2426
$dotKey = $val["k"];
2527
$final[$dotKey] ??= [];
2628

29+
if (!in_array($val["la"], $this->languages)) {
30+
$this->languages[] = $val["la"];
31+
}
32+
2733
$final[$dotKey][$val["la"]] = $val["vs"];
2834
}
2935
} else {
3036
foreach ($value["vs"] as $v) {
3137
$dotKey = "{$value["k"]}.{$v['k']}";
3238
$final[$dotKey] ??= [];
3339

40+
if (!in_array($$value["la"], $this->languages)) {
41+
$this->languages[] = $$value["la"];
42+
}
43+
3444
$final[$dotKey][$value["la"]] = $v['arr'];
3545
}
3646
}
@@ -345,6 +355,7 @@ protected function fromPhpFile($file, $path, $namespace)
345355
echo json_encode([
346356
'default' => \Illuminate\Support\Facades\App::currentLocale(),
347357
'translations' => $translator->all(),
358+
'languages' => $translator->languages,
348359
'paths' => array_keys($translator->paths),
349360
'values' => array_keys($translator->values),
350361
'params' => array_map(fn($p) => json_decode($p, true), array_keys($translator->paramResults)),

src/features/translation.ts

Lines changed: 125 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,114 @@ import { findHoverMatchesInDoc } from "@src/support/doc";
99
import { detectedRange, detectInDoc } from "@src/support/parser";
1010
import { wordMatchRegex } from "@src/support/patterns";
1111
import { relativePath } from "@src/support/project";
12-
import { contract, facade } from "@src/support/util";
12+
import { contract, createIndexMapping, facade } from "@src/support/util";
13+
import { AutocompleteParsingResult } from "@src/types";
1314
import * as vscode from "vscode";
1415
import { FeatureTag, HoverProvider, LinkProvider } from "..";
1516

1617
const toFind: FeatureTag = [
1718
{
1819
class: [contract("Translation\\Translator")],
1920
method: ["get", "choice"],
20-
argumentIndex: 0,
21-
},
21+
},
2222
{
2323
class: facade("Lang"),
24-
method: ["has", "hasForLocale", "get", "getForLocale", "choice"],
25-
argumentIndex: [0, 1],
24+
method: ["has", "hasForLocale", "get", "choice"],
2625
},
2726
{
2827
method: ["__", "trans", "trans_choice", "@lang"],
29-
argumentIndex: [0, 1],
3028
},
3129
];
3230

33-
const getDefault = (translation: TranslationItem) => {
34-
const langDefault = getTranslations().items.default;
31+
type ArgIndexMap = Record<string, Record<string, number>>;
32+
33+
const paramArgIndexes = createIndexMapping([
34+
[
35+
contract("Translation\\Translator"),
36+
{
37+
get: 1,
38+
choice: 2,
39+
},
40+
],
41+
[
42+
"",
43+
{
44+
__: 1,
45+
trans: 1,
46+
"@lang": 1,
47+
trans_choice: 2,
48+
},
49+
],
50+
[
51+
facade("Lang"),
52+
{
53+
get: 1,
54+
choice: 2,
55+
},
56+
],
57+
]);
58+
59+
const localeArgIndexes = createIndexMapping([
60+
[
61+
contract("Translation\\Translator"),
62+
{
63+
get: 2,
64+
choice: 3,
65+
},
66+
],
67+
[
68+
"",
69+
{
70+
__: 2,
71+
trans: 2,
72+
"@lang": 2,
73+
trans_choice: 3,
74+
},
75+
],
76+
[
77+
facade("Lang"),
78+
{
79+
has: 1,
80+
hasForLocale: 1,
81+
get: 2,
82+
choice: 3,
83+
},
84+
],
85+
]);
86+
87+
const getLang = (
88+
item: AutocompleteParsingResult.MethodCall,
89+
): string | undefined => {
90+
const localeArgIndex = localeArgIndexes.get(
91+
item.className,
92+
item.methodName,
93+
);
94+
95+
const locale = (
96+
item.arguments.children as AutocompleteParsingResult.Argument[]
97+
).find((arg, i) => arg.name === "locale" || i === localeArgIndex);
3598

36-
return translation[langDefault] ?? translation[Object.keys(translation)[0]];
99+
return locale?.children.length
100+
? (locale.children as AutocompleteParsingResult.StringValue[])[0].value
101+
: undefined;
102+
};
103+
104+
const getTranslationItemByLang = (
105+
translation: TranslationItem,
106+
lang?: string,
107+
) => {
108+
return (
109+
translation[lang ?? getTranslations().items.default] ??
110+
translation[Object.keys(translation)[0]]
111+
);
37112
};
38113

39114
export const linkProvider: LinkProvider = (doc: vscode.TextDocument) => {
40115
return detectInDoc<vscode.DocumentLink, "string">(
41116
doc,
42117
toFind,
43118
getTranslations,
44-
({ param, index }) => {
119+
({ param, index, item }) => {
45120
if (index !== 0) {
46121
return null;
47122
}
@@ -53,7 +128,10 @@ export const linkProvider: LinkProvider = (doc: vscode.TextDocument) => {
53128
return null;
54129
}
55130

56-
const def = getDefault(translation);
131+
const def = getTranslationItemByLang(
132+
translation,
133+
getLang(item as AutocompleteParsingResult.MethodCall),
134+
);
57135

58136
return new vscode.DocumentLink(
59137
detectedRange(param),
@@ -134,10 +212,42 @@ export const completionProvider = {
134212
token: vscode.CancellationToken,
135213
context: vscode.CompletionContext,
136214
): vscode.CompletionItem[] {
137-
if (result.isParamIndex(1)) {
215+
const localeArgIndex = localeArgIndexes.get(
216+
result.class(),
217+
result.func(),
218+
);
219+
const paramArgIndex = paramArgIndexes.get(
220+
result.class(),
221+
result.func(),
222+
);
223+
224+
if (result.isParamIndex(paramArgIndex ?? -1)) {
138225
return this.getParameterCompletionItems(result, document, position);
139226
}
140227

228+
if (
229+
result.isParamIndex(localeArgIndex ?? -1) ||
230+
result.isArgumentNamed("locale")
231+
) {
232+
return getTranslations().items.languages.map((lang) => {
233+
let completionItem = new vscode.CompletionItem(
234+
lang,
235+
vscode.CompletionItemKind.Value,
236+
);
237+
238+
completionItem.range = document.getWordRangeAtPosition(
239+
position,
240+
wordMatchRegex,
241+
);
242+
243+
return completionItem;
244+
});
245+
}
246+
247+
if (!result.isParamIndex(0)) {
248+
return [];
249+
}
250+
141251
const totalTranslationItems = Object.entries(
142252
getTranslations().items.translations,
143253
).length;
@@ -157,7 +267,8 @@ export const completionProvider = {
157267
if (totalTranslationItems < 200) {
158268
// This will bomb if we have too many translations,
159269
// 200 is an arbitrary but probably safe number
160-
completionItem.detail = getDefault(translations).value;
270+
completionItem.detail =
271+
getTranslationItemByLang(translations).value;
161272
}
162273

163274
return completionItem;
@@ -182,7 +293,7 @@ export const completionProvider = {
182293
return Object.entries(getTranslations().items.translations)
183294
.filter(([key, value]) => key === result.param(0).value)
184295
.map(([key, value]) => {
185-
return getDefault(value)
296+
return getTranslationItemByLang(value)
186297
.params.filter((param) => {
187298
return true;
188299
// TODO: Fix this....

src/parser/AutocompleteResult.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ export default class AutocompleteResult {
117117
return this.param()?.name ?? null;
118118
}
119119

120+
public isArgumentNamed(name: string) {
121+
return this.argumentName() === name;
122+
}
123+
120124
public isParamIndex(index: number) {
121125
return this.paramIndex() === index;
122126
}

src/repositories/translations.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ interface TranslationGroupResult {
1717
translations: {
1818
[key: string]: TranslationItem;
1919
};
20+
languages: string[];
2021
}
2122

2223
interface TranslationGroupPhpResult {
@@ -30,6 +31,7 @@ interface TranslationGroupPhpResult {
3031
paths: string[];
3132
values: string[];
3233
to_watch: string[];
34+
languages: string[];
3335
}
3436

3537
let dirsToWatch: string[] | null = null;
@@ -63,6 +65,7 @@ const load = () => {
6365
return {
6466
default: res.default,
6567
translations: result,
68+
languages: res.languages,
6669
};
6770
});
6871
};

src/support/util.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,24 @@ export const waitForValue = <T>(
125125

126126
checkForValue();
127127
});
128+
129+
export const createIndexMapping = (
130+
items: [string | string[], Record<string, number>][],
131+
) => {
132+
const mapping: Record<string, Record<string, number>> = {};
133+
134+
items.forEach(([keys, value]) => {
135+
keys = toArray(keys);
136+
137+
keys.forEach((key) => {
138+
mapping[key] = value;
139+
});
140+
});
141+
142+
return {
143+
mapping,
144+
get(className: string | null, methodName: string | null) {
145+
return mapping[className ?? ""][methodName ?? ""] ?? null;
146+
},
147+
};
148+
};

src/templates/translations.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ $translator = new class
1414
1515
public $directoriesToWatch = [];
1616
17+
public $languages = [];
18+
1719
public function all()
1820
{
1921
$final = [];
@@ -24,13 +26,21 @@ $translator = new class
2426
$dotKey = $val["k"];
2527
$final[$dotKey] ??= [];
2628
29+
if (!in_array($val["la"], $this->languages)) {
30+
$this->languages[] = $val["la"];
31+
}
32+
2733
$final[$dotKey][$val["la"]] = $val["vs"];
2834
}
2935
} else {
3036
foreach ($value["vs"] as $v) {
3137
$dotKey = "{$value["k"]}.{$v['k']}";
3238
$final[$dotKey] ??= [];
3339
40+
if (!in_array($$value["la"], $this->languages)) {
41+
$this->languages[] = $$value["la"];
42+
}
43+
3444
$final[$dotKey][$value["la"]] = $v['arr'];
3545
}
3646
}
@@ -345,6 +355,7 @@ $translator = new class
345355
echo json_encode([
346356
'default' => \\Illuminate\\Support\\Facades\\App::currentLocale(),
347357
'translations' => $translator->all(),
358+
'languages' => $translator->languages,
348359
'paths' => array_keys($translator->paths),
349360
'values' => array_keys($translator->values),
350361
'params' => array_map(fn($p) => json_decode($p, true), array_keys($translator->paramResults)),

0 commit comments

Comments
 (0)