Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client
117
fork

Configure Feed

Select the types of activity you want to include in your feed.

1# Internationalization 2 3We want the official Bluesky app to be supported in as many languages as possible. If you want to help us translate the app, please get involved on [Crowdin](https://bluesky.crowdin.com/bluesky-social) or open an issue on the [Bluesky app repo on GitHub](https://github.com/bluesky-social/social-app). 4 5## Tools 6 7- We use Crowdin to manage translations. 8 - Bluesky Crowdin: https://bluesky.crowdin.com/bluesky-social 9 - Introduction to Crowdin: https://support.crowdin.com/for-translators/ 10- We use Lingui to implement translations. You can find the documentation [here](https://lingui.dev/). 11 12## Translators 13 14Much of the app is translated by community contributions. (We <3 our translators!) If you want to participate in the translation of the app, read this section. 15 16### Using Crowdin 17 18[Crowdin](https://bluesky.crowdin.com/bluesky-social) is our primary tool for managing translations. There are two roles: 19 20- **Proof-readers**. Can create new translations and approve submitted translations. 21- **Translators**. Can create new translations. 22 23All translations must be approved by proof-readers before they are accepted into the app. 24 25### Using other platforms 26 27You may contribute PRs separately from Crowdin, however we strongly recommend using Crowdin to avoid conflicts. 28 29### Code of conduct on Crowdin 30 31Please treat everyone with respect. Proof-readers are given final say on translations. Translators who frequently come into conflict with other translators, or who contribute noticably incorrect translations, will have their membership to the Crowdin project revoked. 32 33### Adding a new language 34 35You can request a new language be added to the project by clicking **Request New Language** on [Crowdin](https://bluesky.crowdin.com/bluesky-social) or you can create a [GitHub issue](https://github.com/bluesky-social/social-app/issues). 36 37Please only request a new language when you are certain you will be able to contribute a substantive portion of translations for the language. 38 39## Maintainers 40 41Install the [Crowdin CLI](https://crowdin.github.io/crowdin-cli/). You will need to [configure your API token](https://crowdin.github.io/crowdin-cli/configuration) to access the project. 42 43### English source-file sync with Crowdin 44 45Every night, a GitHub action will run `pnpm intl:extract` to update the english `messages.po` file. This will be automatically synced with Crowdin. Crowdin should notify all subscribed users of new translations. 46 47### Release process 48 491. Pull main and create a branch. 501. Run `pnpm intl:release` to fetch all translation updates from Crowdin and extract all `.po` files so that they're synced with the latest code. Commit that. 511. Create a PR, ensure the translations all look correct, and merge. 521. If needed: 53 1. Merge all approved translation PRs (contributions from outside crowdin). 54 1. Run `pnpm intl:push` to sync Crowdin with the state of the repo. 55 56### Testing the translations in Crowdin 57 58You can run `pnpm intl:pull` to pull the currently-approved translations from Crowdin. 59 60## Developers 61 62### Adding new strings 63 64When adding a new string, do it as follows: 65```jsx 66// Before 67import { Text } from "react-native"; 68 69<Text>Hello World</Text> 70``` 71 72```jsx 73// After 74import { Text } from "react-native"; 75import { Trans } from "@lingui/react/macro"; 76 77<Text><Trans>Hello World</Trans></Text> 78``` 79 80The `<Trans>` macro will extract the string and add it to the catalog. It is not really a component, but a macro. Further reading [here](https://lingui.dev/ref/macro.html) 81 82However sometimes you will run into this case: 83```jsx 84// Before 85import { Text } from "react-native"; 86 87const text = "Hello World"; 88<Text accessibilityLabel="Label is here">{text}</Text> 89``` 90In this case, you can use the `useLingui()` hook: 91```jsx 92import { msg } from "@lingui/core/macro"; 93import { useLingui } from "@lingui/react"; 94 95const { _ } = useLingui(); 96return <Text accessibilityLabel={_(msg`Label is here`)}>{text}</Text> 97``` 98 99NEW: the latest Lingui version introduced a new macro version of the `useLingui` hook which lets you do this: 100 101```jsx 102import { useLingui } from "@lingui/react/macro"; 103 104const { t } = useLingui(); 105return <Text accessibilityLabel={t`Label is here`}>{text}</Text> 106``` 107 108If you want to do this outside of a React component, you can use the global `t` macro instead (note: this won't react to changes if the locale is switched dynamically within the app): 109```jsx 110import { t } from "@lingui/core/macro"; 111 112// not ideal - t only gets called once at module evaluation time 113const text = t`Hello World`; 114 115// however, this is suitable for strings that are ephemeral: 116function sayHello() { 117 Toast.show(t`Hello World`); // Each time the toast shows, the current locale at that moment is used 118} 119``` 120 121We can then run `pnpm intl:extract` to update the catalog in `src/locale/locales/{locale}/messages.po`. This will add the new string to the catalog. 122We can then run `pnpm intl:compile` to update the translation files in `src/locale/locales/{locale}/messages.js`. This will add the new string to the translation files. 123The configuration for translations is defined in `lingui.config.js` 124 125So the workflow is as follows: 1261. Wrap messages in Trans macro 1272. Run `pnpm intl:extract` command to generate message catalogs 1283. Translate message catalogs (send them to translators usually) 1294. Run `pnpm intl:compile` to create runtime catalogs 1305. Load runtime catalog 1316. Enjoy translated app! 132 133### Common pitfalls 134 135These pitfalls are memoization pitfalls that will cause the components to not re-render when the locale is changed -- causing stale translations to be shown. 136 137```jsx 138import { msg } from "@lingui/core/macro"; 139import { i18n } from "@lingui/core"; 140 141const welcomeMessage = msg`Welcome!`; 142 143// ❌ Bad! This code won't work 144export function Welcome() { 145 const buggyWelcome = useMemo(() => { 146 return i18n._(welcomeMessage); 147 }, []); 148 149 return <div>{buggyWelcome}</div>; 150} 151 152// ❌ Bad! This code won't work either because the reference to i18n does not change 153export function Welcome() { 154 const { i18n } = useLingui(); 155 156 const buggyWelcome = useMemo(() => { 157 return i18n._(welcomeMessage); 158 }, [i18n]); 159 160 return <div>{buggyWelcome}</div>; 161} 162 163// ✅ Good! `useMemo` has i18n context in the dependency 164export function Welcome() { 165 const linguiCtx = useLingui(); 166 167 const welcome = useMemo(() => { 168 return linguiCtx.i18n._(welcomeMessage); 169 }, [linguiCtx]); 170 171 return <div>{welcome}</div>; 172} 173 174// 🤩 Better! `useMemo` consumes the `_` function from the Lingui context 175export function Welcome() { 176 const { _ } = useLingui(); 177 178 const welcome = useMemo(() => { 179 return _(welcomeMessage); 180 }, [_]); 181 182 return <div>{welcome}</div>; 183} 184```