This repository has been archived by the owner on Jan 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 477
/
Locales.ts
84 lines (72 loc) · 3.02 KB
/
Locales.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import JsonFile from '@expo/json-file';
import * as fs from 'fs-extra';
import { join } from 'path';
import { XcodeProject } from 'xcode';
import { ExpoConfig } from '../Config.types';
import { addWarningIOS } from '../WarningAggregator';
import { addFileToGroup, ensureGroupRecursively, getProjectName } from './utils/Xcodeproj';
type LocaleJson = Record<string, string>;
type ResolvedLocalesJson = Record<string, LocaleJson>;
type ExpoConfigLocales = NonNullable<ExpoConfig['locales']>;
export function getLocales(config: ExpoConfig): Record<string, string | LocaleJson> | null {
return config.locales ?? null;
}
export async function setLocalesAsync(
config: ExpoConfig,
{ projectRoot, project }: { projectRoot: string; project: XcodeProject }
): Promise<XcodeProject> {
const locales = getLocales(config);
if (!locales) {
return project;
}
// possibly validate CFBundleAllowMixedLocalizations is enabled
const localesMap = await getResolvedLocalesAsync(projectRoot, locales);
const projectName = getProjectName(projectRoot);
const supportingDirectory = join(projectRoot, 'ios', projectName, 'Supporting');
// TODO: Should we delete all before running? Revisit after we land on a lock file.
const stringName = 'InfoPlist.strings';
for (const [lang, localizationObj] of Object.entries(localesMap)) {
const dir = join(supportingDirectory, `${lang}.lproj`);
await fs.ensureDir(dir);
const strings = join(dir, stringName);
const buffer = [];
for (const [plistKey, localVersion] of Object.entries(localizationObj)) {
buffer.push(`${plistKey} = "${localVersion}";`);
}
// Write the file to the file system.
await fs.writeFile(strings, buffer.join('\n'));
// deep find the correct folder
const group = ensureGroupRecursively(project, `${projectName}/Supporting/${lang}.lproj`);
// Ensure the file doesn't already exist
if (!group?.children.some(({ comment }) => comment === stringName)) {
// Only write the file if it doesn't already exist.
project = addFileToGroup(strings, `${projectName}/Supporting/${lang}.lproj`, project);
}
}
return project;
}
export async function getResolvedLocalesAsync(
projectRoot: string,
input: ExpoConfigLocales
): Promise<ResolvedLocalesJson> {
const locales: ResolvedLocalesJson = {};
for (const [lang, localeJsonPath] of Object.entries(input)) {
if (typeof localeJsonPath === 'string') {
try {
locales[lang] = await JsonFile.readAsync(join(projectRoot, localeJsonPath));
} catch (e) {
// Add a warning when a json file cannot be parsed.
addWarningIOS(
`locales-${lang}`,
`Failed to parse JSON of locale file for language: ${lang}`,
'https://docs.expo.io/distribution/app-stores/#localizing-your-ios-app'
);
}
} else {
// In the off chance that someone defined the locales json in the config, pass it directly to the object.
// We do this to make the types more elegant.
locales[lang] = localeJsonPath;
}
}
return locales;
}