Skip to content

Commit

Permalink
feat: support expo config plugin (#25)
Browse files Browse the repository at this point in the history
To make it easier for people using this library with Expo, I added support for the Expo config plugin to enable automatic generation of native configurations. This feature is currently in the experimental phase, so any feedback is greatly appreciated!

Simply add the config plugin to your `app.json` file and specify the list of supported languages:

```json
{
  "expo": {
    // ...
    "plugins": [
      [
        "react-native-localization-settings", 
        { 
          "languages": ["en", "pl"] 
        }
      ]
    ]
  }
}
```

and run `npx expo prebuild`.
  • Loading branch information
jakex7 authored Nov 10, 2024
1 parent d6d4b89 commit 35ed4bf
Show file tree
Hide file tree
Showing 9 changed files with 3,663 additions and 54 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ android/keystores/debug.keystore

# Expo
.expo/
tsconfig.tsbuildinfo

# Turborepo
.turbo/
Expand Down
1 change: 1 addition & 0 deletions app.plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./plugin/build');
11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
"ios",
"cpp",
"*.podspec",
"plugin",
"app.plugin.js",
"!plugin/tsconfig.*",
"!lib/typescript/example",
"!ios/build",
"!android/build",
Expand All @@ -30,7 +33,10 @@
"test": "jest",
"typecheck": "tsc --noEmit",
"lint": "eslint \"**/*.{js,ts,tsx}\"",
"prepack": "bob build",
"plugin-dev": "expo-module build plugin",
"plugin-build": "tsc --build plugin",
"plugin-clean": "expo-module clean plugin",
"prepack": "bob build && yarn plugin-clean && yarn plugin-build",
"release": "release-it",
"example": "yarn --cwd example",
"bootstrap": "yarn example && yarn install && yarn example pods",
Expand Down Expand Up @@ -64,14 +70,15 @@
"eslint": "^8.4.1",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"expo-module-scripts": "3.5.4",
"jest": "^28.1.1",
"pod-install": "^0.1.0",
"prettier": "^2.0.5",
"react": "18.2.0",
"react-native": "0.71.6",
"react-native-builder-bob": "^0.20.0",
"release-it": "^15.0.0",
"typescript": "^4.5.2"
"typescript": "^5.6.3"
},
"resolutions": {
"@types/react": "17.0.21"
Expand Down
40 changes: 40 additions & 0 deletions plugin/src/android.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
AndroidConfig,
ConfigPlugin,
withAndroidManifest,
} from '@expo/config-plugins';
import path from 'path';
import fs from 'fs';

export const withAndroidLanguages: ConfigPlugin<{
languages?: string[];
}> = (config, { languages = [] } = {}) => {
config = withAndroidManifest(config, (config) => {

Check warning on line 12 in plugin/src/android.ts

View workflow job for this annotation

GitHub Actions / lint

'config' is already declared in the upper scope on line 11 column 7
const mainApplication = AndroidConfig.Manifest.getMainApplicationOrThrow(
config.modResults
);

// Add the `android:localeConfig` attribute to the `<application>` tag
mainApplication.$['android:localeConfig'] = '@xml/locales_config';

const localesConfigPath = path.join(
config.modRequest.platformProjectRoot,
'app/src/main/res/xml/locales_config.xml'
);
// Ensure the `res/xml` directory exists
fs.mkdirSync(path.dirname(localesConfigPath), { recursive: true });

// Prepare locales_config.xml content
const xmlContent = `<?xml version="1.0" encoding="utf-8"?>
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
${languages.map((lang) => `<locale android:name="${lang}" />`).join('\n ')}
</locale-config>`;

// Write the `res/xml/locales_config.xml` file
fs.writeFileSync(localesConfigPath, xmlContent);

return config;
});

return config;
};
14 changes: 14 additions & 0 deletions plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ConfigPlugin } from '@expo/config-plugins';
import { withAndroidLanguages } from './android';
import { withIosLanguages } from './ios';

const withReactNativeLocalizationSettings: ConfigPlugin<{
languages?: string[];
}> = (config, { languages = [] } = {}) => {
config = withAndroidLanguages(config, { languages });
config = withIosLanguages(config, { languages });

return config;
};

export default withReactNativeLocalizationSettings;
49 changes: 49 additions & 0 deletions plugin/src/ios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
ConfigPlugin,
IOSConfig,
withXcodeProject,
} from '@expo/config-plugins';

const generateLocalizableContent = (languages: string[]) => `{
"sourceLanguage" : "Base",
"strings" : {
"react-native-localization-settings" : {
"extractionState" : "manual",
"localizations" : {
"base" : {"stringUnit" : {"state" : "translated","value" : ""}},
${languages
.map(
(lang) =>
`"${lang}" : {"stringUnit" : {"state" : "translated","value" : ""}},`
)
.join('\n ')}
}
}
},
"version" : "1.0"
}`;

export const withIosLanguages: ConfigPlugin<{
languages?: string[];
}> = (config, { languages = [] } = {}) => {
config = withXcodeProject(config, (config) => {

Check warning on line 29 in plugin/src/ios.ts

View workflow job for this annotation

GitHub Actions / lint

'config' is already declared in the upper scope on line 28 column 7
const project = config.modResults;
const projectObject =
project.pbxProjectSection()[project.getFirstProject().uuid];
if (projectObject) {
// Add known regions to the project
projectObject.knownRegions = ['Base', ...languages];

// Write the Localizable.xcstrings file
IOSConfig.XcodeProjectFile.createBuildSourceFile({
project,
nativeProjectRoot: config.modRequest.platformProjectRoot,
filePath: 'Localizable.xcstrings',
fileContents: generateLocalizableContent(languages),
overwrite: true,
});
}
return config;
});
return config;
};
9 changes: 9 additions & 0 deletions plugin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "expo-module-scripts/tsconfig.plugin",
"compilerOptions": {
"outDir": "build",
"rootDir": "src"
},
"include": ["./src"],
"exclude": ["**/__mocks__/*", "**/__tests__/*"]
}
1 change: 0 additions & 1 deletion tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

{
"extends": "./tsconfig",
"exclude": ["example"]
Expand Down
Loading

0 comments on commit 35ed4bf

Please sign in to comment.