Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/381.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何将一个本地Expo应用程序国际化?_Javascript_Reactjs_React Native_Internationalization_Expo - Fatal编程技术网

Javascript 如何将一个本地Expo应用程序国际化?

Javascript 如何将一个本地Expo应用程序国际化?,javascript,reactjs,react-native,internationalization,expo,Javascript,Reactjs,React Native,Internationalization,Expo,制作React应用程序时,建议使用哪种技术 我正在考虑编写以下代码: 创建React上下文“语言” 创建不同的模块,导出包含每种语言“pt”、“en”、“fr”、“sp”、“it”所有字符串的映射 尝试使用语言上下文提供程序提供的方法从我的启动屏幕中的AsyncStorage加载默认语言 如果找不到,请根据他的位置获取用户语言 对我来说,这是有道理的,但可能还有其他更简单的方法来达到同样的目的,让我感觉更专业 // This is my Languages Context import Reac

制作React应用程序时,建议使用哪种技术

我正在考虑编写以下代码:

  • 创建React上下文“语言”
  • 创建不同的模块,导出包含每种语言“pt”、“en”、“fr”、“sp”、“it”所有字符串的映射
  • 尝试使用语言上下文提供程序提供的方法从我的启动屏幕中的AsyncStorage加载默认语言
  • 如果找不到,请根据他的位置获取用户语言
  • 对我来说,这是有道理的,但可能还有其他更简单的方法来达到同样的目的,让我感觉更专业

    // This is my Languages Context
    import React, { createContext, useState } from "react";
    import * as Localization from "expo-localization";
    
    import { VALID_LANGUAGES } from "../../utils/languages/constants"; // "English", "Spanish", "Portuguese"...
    import languages from "../../languages"; // en, sp, pt, ... modules with all texts (key, value)
    import AsyncStorage from "../../lib/async-storage/AsyncStorage";
    
    const LanguagesContext = createContext(null);
    
    export default LanguagesContext;
    
    export function LanguagesProvider({ children }) {
      const [language, setLanguage] = useState(undefined);
    
      const loadLanguage = async () => {
        // Get the default language from async storage
        const language = await AsyncStorage.getData("language");
    
        // TODO - if undefined -> get user location and use the corresponding lang
        // TODO - if not supported, use english
    
        if (!language) {
          setLanguage(VALID_LANGUAGES[0]);
        }
      };
    
      const changeLanguage = async (language) => {
        // Update state
        setLanguage(language);
    
        // Save language in async storage
        await AsyncStorage.storeData("language", language);
      };
    
      return (
        <LanguagesContext.Provider
          value={{ language, loadLanguage, changeLanguage }}
        >
          {children}
        </LanguagesContext.Provider>
      );
    }
    
    export { LanguagesProvider };
    
    //这是我的语言上下文
    从“React”导入React,{createContext,useState};
    从“世博会本地化”导入*作为本地化;
    从“./../utils/LANGUAGES/constants”;//“英语”、“西班牙语”、“葡萄牙语”。。。
    从“../../languages”;//导入语言恩,sp,pt。。。包含所有文本(键、值)的模块
    从“../../lib/async storage/async storage”导入异步存储;
    const LanguagesContext=createContext(null);
    导出默认语言上下文;
    导出函数语言Provider({children}){
    const[language,setLanguage]=useState(未定义);
    const loadLanguage=async()=>{
    //从异步存储中获取默认语言
    const language=await AsyncStorage.getData(“语言”);
    //TODO-如果未定义->获取用户位置并使用相应的语言
    //TODO-如果不支持,请使用英语
    如果(!语言){
    setLanguage(有效的_语言[0]);
    }
    };
    const changeLanguage=异步(语言)=>{
    //更新状态
    语言;
    //在异步存储中保存语言
    等待AsyncStorage.storeData(“语言”,语言);
    };
    返回(
    {儿童}
    );
    }
    导出{LanguagesProvider};
    
    我所做的是在我的闪屏组件中使用“loadLanguage”方法,这可以确保应用程序在呈现任何内容之前准备好使用。您认为这项技术怎么样?

    如何使用应用程序中的文本?我想在上下文提供程序中创建另一个方法getAppText(),只是为了从我的语言模块(“en”、“it”、“pt”和……)返回正确的映射

    任何库和示例?


    谢谢。

    首先,您只需启动一个新项目

    $ npx react-native init rn_example_translation
    
    我更愿意创建一个src文件夹来放置我们所有的JS代码,因此我们在下面的项目根目录中修改index.JS,如下所示:

    import {AppRegistry} from 'react-native';
    import App from './src/App';
    import {name as appName} from './app.json';
    
    AppRegistry.registerComponent(appName, () => App);
    
    import {I18nManager} from 'react-native';
    import * as RNLocalize from 'react-native-localize';
    import i18n from 'i18n-js';
    import memoize from 'lodash.memoize';
    
    export const DEFAULT_LANGUAGE = 'en';
    
    export const translationGetters = {
      // lazy requires (metro bundler does not support symlinks)
      en: () => require('./assets/locales/en/translations.json'),
      fr: () => require('./assets/locales/fr/translations.json'),
    };
    
    export const translate = memoize(
      (key, config) => i18n.t(key, config),
      (key, config) => (config ? key + JSON.stringify(config) : key),
    );
    
    export const t = translate;
    
    export const setI18nConfig = (codeLang = null) => {
      // fallback if no available language fits
      const fallback = {languageTag: DEFAULT_LANGUAGE, isRTL: false};
      const lang = codeLang ? {languageTag: codeLang, isRTL: false} : null;
    
    # Use RNLocalize to detect the user system language
      const {languageTag, isRTL} = lang
        ? lang
        : RNLocalize.findBestAvailableLanguage(Object.keys(translationGetters)) ||
          fallback;
    
      // clear translation cache
      translate.cache.clear();
      // update layout direction
      I18nManager.forceRTL(isRTL);
      // set i18n-js config
      i18n.translations = {[languageTag]: translationGetters[languageTag]()};
      i18n.locale = languageTag;
    
      return languageTag;
    };
    
    管理翻译

    我们将使用“i18n js”模块翻译该应用程序,因此我们将使用以下模块安装该应用程序:

    $ npm install --save i18n-js
    
    然后创建一个文件“i18n.js”,其中包含:

    import {I18nManager} from 'react-native';
    import i18n from 'i18n-js';
    import memoize from 'lodash.memoize';
    
    export const DEFAULT_LANGUAGE = 'en';
    
    export const translationGetters = {
      // lazy requires (metro bundler does not support symlinks)
      en: () => require('./assets/locales/en/translations.json'),
      fr: () => require('./assets/locales/fr/translations.json'),
    };
    
    export const translate = memoize(
      (key, config) => i18n.t(key, config),
      (key, config) => (config ? key + JSON.stringify(config) : key),
    );
    
    export const t = translate;
    
    export const setI18nConfig = (codeLang = null) => {
      // fallback if no available language fits
      const fallback = {languageTag: DEFAULT_LANGUAGE, isRTL: false};
      const lang = codeLang ? {languageTag: codeLang, isRTL: false} : null;
    
      const {languageTag, isRTL} = lang ? lang : fallback;
    
      // clear translation cache
      translate.cache.clear();
      // update layout direction
      I18nManager.forceRTL(isRTL);
      // set i18n-js config
      i18n.translations = {[languageTag]: translationGetters[languageTag]()};
      i18n.locale = languageTag;
    
      return languageTag;
    };
    
    然后创建空翻译文件,如下所示:

     './src/assets/locales/en/translations.json' and './src/assets/locales/fr/translations.json'
    
    i18n.t('Hello world!')
    
    现在我们可以用法语和英语翻译app JS字符串,如下所示:

     './src/assets/locales/en/translations.json' and './src/assets/locales/fr/translations.json'
    
    i18n.t('Hello world!')
    
    在应用程序中切换区域设置

    现在,我们将设置一个react上下文以保持当前用户语言,并设置一个开关以向用户提供更改语言的选项。翻译字符串很酷,但翻译的字符串必须与用户语言相匹配

    要使应用程序中的当前用户语言与react上下文保持一致,我们需要在上下文文件夹中创建一个文件'LocalisationContext.js',其中包含:

     import React from 'react';
    
    const LocalizationContext = React.createContext();
    
    export default LocalizationContext;
    
    现在在你的App.js中

    import React, {useEffect, useCallback} from 'react';
    import {StyleSheet} from 'react-native';
    
    import * as i18n from './i18n';
    import LocalizationContext from './context/LocalizationContext';
    import HomeScreen from './HomeScreen';
    
    const App: () => React$Node = () => {
      const [locale, setLocale] = React.useState(i18n.DEFAULT_LANGUAGE);
      const localizationContext = React.useMemo(
        () => ({
          t: (scope, options) => i18n.t(scope, {locale, ...options}),
          locale,
          setLocale,
        }),
        [locale],
      );
    
      return (
        <>
          <LocalizationContext.Provider value={localizationContext}>
            <HomeScreen localizationChange={handleLocalizationChange} />
          </LocalizationContext.Provider>
        </>
      );
    };
    
    然后将app.js修改为

    import React, {useEffect, useCallback} from 'react';
    import {StyleSheet} from 'react-native';
    import * as RNLocalize from 'react-native-localize';
    
    import * as i18n from './i18n';
    import LocalizationContext from './context/LocalizationContext';
    import HomeScreen from './HomeScreen';
    
    const App: () => React$Node = () => {
      const [locale, setLocale] = React.useState(i18n.DEFAULT_LANGUAGE);
      const localizationContext = React.useMemo(
        () => ({
          t: (scope, options) => i18n.t(scope, {locale, ...options}),
          locale,
          setLocale,
        }),
        [locale],
      );
    
      const handleLocalizationChange = useCallback(
        (newLocale) => {
          const newSetLocale = i18n.setI18nConfig(newLocale);
          setLocale(newSetLocale);
        },
        [locale],
      );
    
      useEffect(() => {
        handleLocalizationChange();
    
        RNLocalize.addEventListener('change', handleLocalizationChange);
        return () => {
          RNLocalize.removeEventListener('change', handleLocalizationChange);
        };
      }, []);
    
      return (
        <>
          <LocalizationContext.Provider value={localizationContext}>
            <HomeScreen localizationChange={handleLocalizationChange} />
          </LocalizationContext.Provider>
        </>
      );
    };
    
    生成翻译

    为了生成语言文件,您可以使用i18next scanner。 我们需要在全球范围内安装它

    npm install -g i18next-scanner
    
    使用以下命令在项目目录根目录下创建“i18next scanner.config.js”文件:

      const fs = require('fs');
    const chalk = require('chalk');
    
    module.exports = {
      input: [
        'src/**/*.{js,jsx}',
        // Use ! to filter out files or directories
        '!app/**/*.spec.{js,jsx}',
        '!app/i18n/**',
        '!**/node_modules/**',
      ],
      output: './',
      options: {
        debug: false,
        removeUnusedKeys: true,
        func: {
          list: ['i18next.t', 'i18n.t', 't'],
          extensions: ['.js', '.jsx'],
        },
        trans: {
          component: 'Trans',
          i18nKey: 'i18nKey',
          defaultsKey: 'defaults',
          extensions: [],
          fallbackKey: function (ns, value) {
            return value;
          },
          acorn: {
            ecmaVersion: 10, // defaults to 10
            sourceType: 'module', // defaults to 'module'
            // Check out https://github.com/acornjs/acorn/tree/master/acorn#interface for additional options
          },
        },
        lngs: ['en', 'fr'],
        ns: ['translations'],
        defaultLng: 'en',
        defaultNs: 'translations',
        defaultValue: '__STRING_NOT_TRANSLATED__',
        resource: {
          loadPath: 'src/assets/locales/{{lng}}/{{ns}}.json',
          savePath: 'src/assets/locales/{{lng}}/{{ns}}.json',
          jsonIndent: 2,
          lineEnding: '\n',
        },
        nsSeparator: false, // namespace separator
        keySeparator: false, // key separator
        interpolation: {
          prefix: '{{',
          suffix: '}}',
        },
      },
      transform: function customTransform(file, enc, done) {
        'use strict';
        const parser = this.parser;
    
        const options = {
          presets: ['@babel/preset-flow'],
          plugins: [
            '@babel/plugin-syntax-jsx',
            '@babel/plugin-proposal-class-properties',
          ],
          configFile: false,
        };
    
        const content = fs.readFileSync(file.path, enc);
        let count = 0;
    
        const code = require('@babel/core').transform(content, options);
        parser.parseFuncFromString(
          code.code,
          {list: ['i18next._', 'i18next.__']},
          (key, options) => {
            parser.set(
              key,
              Object.assign({}, options, {
                nsSeparator: false,
                keySeparator: false,
              }),
            );
            ++count;
          },
        );
    
        if (count > 0) {
          console.log(
            `i18next-scanner: count=${chalk.cyan(count)}, file=${chalk.yellow(
              JSON.stringify(file.relative),
            )}`,
          );
        }
    
        done();
      },
    };
    
    在这里,我们可以使用以下命令:

    $ i18next-scanner
    
    现在它将生成预填充翻译文件

    './src/assets/locales/en/translations.json' and './src/assets/locales/fr/translations.json'.
    
    我们只需要通过正确的翻译来更改这些文件

    现在运行应用程序

    npx react-native run-android
    

    它将成功运行。

    为什么不使用设备的操作系统语言而不是位置来设置默认语言?