Skip to content

Commit

Permalink
feat: react native docs (#1506)
Browse files Browse the repository at this point in the history
  • Loading branch information
vonovak authored May 4, 2023
1 parent 1172b06 commit eb0ceac
Show file tree
Hide file tree
Showing 26 changed files with 11,153 additions and 106 deletions.
27 changes: 27 additions & 0 deletions examples/react-native/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
node_modules/
.expo/
dist/
npm-debug.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
*.orig.*
web-build/

# macOS
.DS_Store

# Temporary files created by Metro to check the health of the file watcher
.metro-health-check*

# js translation files should be generated as part of build process
#src/locales/**/*.js

.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
7 changes: 7 additions & 0 deletions examples/react-native/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"singleQuote": false,
"trailingComma": "all",
"tabWidth": 2,
"bracketSpacing": true,
"printWidth": 90
}
1 change: 1 addition & 0 deletions examples/react-native/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
27 changes: 27 additions & 0 deletions examples/react-native/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import "@formatjs/intl-locale/polyfill";

import "@formatjs/intl-pluralrules/polyfill";
import "@formatjs/intl-pluralrules/locale-data/en"; // locale-data for en
import "@formatjs/intl-pluralrules/locale-data/cs"; // locale-data for cs

import React from "react";
import { Text } from "react-native";
import { i18n } from "@lingui/core";
import { I18nProvider, TransRenderProps } from "@lingui/react";

import { messages } from "./src/locales/en/messages.js";
import { Body } from "./src/MainScreen";

i18n.loadAndActivate({ locale: "en", messages });

const DefaultComponent = (props: TransRenderProps) => {
return <Text>{props.children}</Text>;
};

export default function Root() {
return (
<I18nProvider i18n={i18n} defaultComponent={DefaultComponent}>
<Body />
</I18nProvider>
);
}
3 changes: 3 additions & 0 deletions examples/react-native/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Lingui Demo App

- see https://lingui.dev/tutorials/react-native
31 changes: 31 additions & 0 deletions examples/react-native/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"expo": {
"name": "js-lingui-demo",
"description": "This a simple demo app for lingui.js",
"slug": "js-lingui-demo",
"version": "2.0.1",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
Binary file added examples/react-native/assets/adaptive-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/react-native/assets/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/react-native/assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/react-native/assets/splash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions examples/react-native/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = function (api) {
api.cache(false);
return {
plugins: ["macros"],
presets: ["babel-preset-expo"],
};
};
12 changes: 12 additions & 0 deletions examples/react-native/lingui.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/** @type {import('@lingui/conf').LinguiConfig} */
module.exports = {
locales: ["en", "cs"],
sourceLocale: "en",
catalogs: [
{
path: "src/locales/{locale}/messages",
include: ["src"],
},
],
format: "po",
};
16 changes: 16 additions & 0 deletions examples/react-native/metro.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require("expo/metro-config");

module.exports = (() => {
const config = getDefaultConfig(__dirname);

const { resolver } = config;

config.resolver = {
...resolver,
// NOTE: in future, this will be enabled by default
unstable_enablePackageExports: true,
};

return config;
})();
39 changes: 39 additions & 0 deletions examples/react-native/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "lingui-demo",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start -c",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"extract": "lingui extract",
"compile": "lingui compile",
"no-dev": "npx expo start --no-dev --minify",
"inspectBundle": "npx react-native-bundle-visualizer"
},
"dependencies": {
"@formatjs/intl-locale": "^3.1.1",
"@formatjs/intl-pluralrules": "^5.1.10",
"@lingui/core": "^4.0.0",
"@lingui/react": "^4.0.0",
"expo": "~48.0.11",
"expo-status-bar": "~1.4.4",
"expo-updates": "~0.16.4",
"react": "18.2.0",
"react-native": "0.71.7"
},
"resolutions": {
"metro": "0.76.2"
},
"devDependencies": {
"@babel/core": "^7.21.0",
"@lingui/cli": "^4.0.0",
"@lingui/macro": "^4.0.0",
"@types/react": "~18.0.14",
"babel-plugin-macros": "^3.1.0",
"prettier": "^2.8.4",
"typescript": "^4.9.4"
},
"private": true
}
13 changes: 13 additions & 0 deletions examples/react-native/src/Components.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { TextProps, Text } from "react-native";

export const Heading = (props: Omit<TextProps, "style">) => {
return (
<Text
style={{
fontSize: 20,
fontWeight: "bold",
}}
{...props}
/>
);
};
121 changes: 121 additions & 0 deletions examples/react-native/src/MainScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import React, { useState } from "react";
import { StyleSheet, Text, View, Alert, SafeAreaView } from "react-native";
import { Plural, SelectOrdinal, t, Trans } from "@lingui/macro";
import { useLingui } from "@lingui/react";
import { Button } from "./PaddedButton";
import { Heading } from "./Components";

export const Body = React.memo(() => {
const [messages, setMessages] = useState<string[]>([]);
const { i18n } = useLingui();

const markAllAsRead = () => {
// NOTE - here we're implicitly using the i18n instance that does NOT come from the React context, but from @lingui/core
// this is because there is nothing that would need to re-render: we're just calling a function and displaying its result in an alert
Alert.alert("", t`Do you want to set all your messages as read?`, [
{
text: t`Yes`,
onPress: () => {
setMessages([]);
},
},
{
text: t`Cancel`,
style: "cancel",
},
]);
};

const loadAndActivateLocale = () => {
const activeLanguage = i18n.locale;
const newActiveLanguage = activeLanguage === "en" ? "cs" : "en";
const catalog =
newActiveLanguage === "en"
? require("./locales/en/messages.js")
: require("./locales/cs/messages.js");
i18n.load(newActiveLanguage, catalog.messages);
i18n.activate(newActiveLanguage);
};

return (
<SafeAreaView style={styles.container}>
<Button
onPress={loadAndActivateLocale}
title={t`Toggle language to ${i18n.locale === "en" ? "cs" : "en"}`}
/>
<Inbox
markAsRead={markAllAsRead}
messages={messages}
addMessage={() => {
setMessages((prevMessages) =>
prevMessages.concat([`message # ${prevMessages.length + 1}`]),
);
}}
/>
</SafeAreaView>
);
});

const Inbox = ({
messages,
markAsRead,
addMessage,
}: {
messages: string[];
markAsRead: () => void;
addMessage: () => void;
}) => {
const messagesCount = messages.length;

return (
<View style={styles.container}>
<View style={styles.container2}>
<Trans render={Heading}>Message Inbox</Trans>

<Button onPress={markAsRead} title={t`Mark messages as read`} />
<Button onPress={addMessage} title={t`Add a message to your inbox`} />

<Plural
value={messagesCount}
_0="You have no unread messages"
one="There's # message in your inbox"
few="There're # messages in your inbox"
other="There're # messages in your inbox"
/>
{messages.map((message, index) => {
const messageIndex = index + 1;
return (
<View key={messageIndex} style={{ flexDirection: "row" }}>
<Text>{message}, </Text>
<Trans>order: </Trans>
<SelectOrdinal
value={messageIndex}
one="#st message"
two="#nd message"
few="#rd message"
other="#th message"
/>
</View>
);
})}
</View>
</View>
);
};

const styles = StyleSheet.create({
container: {
paddingTop: 40,
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
},
container2: {
alignItems: "center",
flex: 1,
},
heading: {
fontSize: 20,
fontWeight: "bold",
},
});
24 changes: 24 additions & 0 deletions examples/react-native/src/PaddedButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {
Button as RNButton,
StyleSheet,
View,
Platform,
ButtonProps,
} from "react-native";
import React from "react";

export const Button = (props: ButtonProps) => (
<View style={styles.margin}>
<RNButton {...props} />
</View>
);

const styles = StyleSheet.create({
margin: {
...Platform.select({
android: {
margin: 10,
},
}),
},
});
1 change: 1 addition & 0 deletions examples/react-native/src/locales/cs/messages.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

1 comment on commit eb0ceac

@vercel
Copy link

@vercel vercel bot commented on eb0ceac May 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.