nativescript-i18n
使用原生标准的 i18n Nativescript 插件
npm i --save nativescript-i18n

nativescript-i18n

这是一个实现 i18n 的插件,使用起来非常简单。

它使用每个平台的原生功能,无需单独的 JS 或 JSON 文件。

它深受 NativeLang此线程 的启发

插件在应用级别定义了一个 L() 方法,因此可以从 XML 和 JS 文件中访问。

请务必阅读重要部分! :smile

致谢

首先感谢 Dan Tamas (@rborn) 过去开发和维护此插件。当他因为优先级调整而不得不放弃它时,他非常友好地将存储库移给了我

感谢 @TheBrousse@ValioStoychev 在 iOS 方面的帮助以及 @alejonext 创建初始模块。

还要感谢所有使此存储库变得更好的 贡献者 :)

用法

在您的应用中安装插件

npm install --save nativescript-i18n

app 文件夹中创建一个名为 i18n 的文件夹,结构如下

app
|
|-- App_Resources
|
[...]
|
|-- i18n
|
|-- en
|- strings.xml
|
|-- es
|- strings.xml

尽早在 app.js 中引入 nativescript-i18nglobals(我在引入 application 模块之前这样做,前两行)。

	require('globals');
require('nativescript-i18n');

如果您使用 TypeScript 并想在代码中使用 L(),您需要将 global 变量转换为 any,如下所示(在您打算使用 L() 的文件中)。您可以在 https://github.com/rborn/nativescript-i18n/issues/57 中了解更多信息。

	declare var global:any;

在代码中使用它的方式如下

XML 文件

简单字符串

	<Label text="{{ L('hello') }}">

它支持一个或多个替换,直接或从模型中替换

	<Label text="{{ L('hello') }}" class="title" textWrap="true" />
<Label text="{{ L('hello_replace','my friend') }}" class="message" textWrap="true" />
<Label text title="{{ L('multi_replace','direct replacement', modelReplacement) }}">

假设您在 strings.xml 中定义了定义,并在模型中定义了替换 modelReplacement 变量

	<string name="hello">Hello!</string>
<string formatted="false" name="hello_replace">Hello %s!</string>
<string formatted="false" name="multi_replace">We can replace directly in xml: %s or from the model: %s</string>

要为 i18n 文件定义自定义路径(除了 App_Resources/i18n),将以下配置添加到项目的 package.json 中

"nativescript-i18n": {
"customLangPath": "app/resources/i18n"
}

如果手机的语言与您定义的语言不匹配,则默认为英语。如果您想设置自己的默认语言,请将以下配置添加到项目的 package.json 中

请注意,在 iOS 上,设备选择的语言将基于 设置 -> 语言与地区 -> 首选语言顺序 中的顺序

"nativescript-i18n": {
"defaultLang": "es"
}

重要

  • 对于所有具有替换的字符串定义,您需要添加 formatted=false

  • 引号和撇号需要转义,如下所示:<string name="with_quotes">Apostrophe: \' and quotes: \"</string>

  • 百分号需要通过设置 formatted="false" 并将其 加倍 来转义:<string formatted="false" name="percent"> Percent Sign: %%</string>

  • 我们需要使用以下格式的 strings.xml,否则应用构建将失败

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    </resources>
  • 我们需要在strings.xml中添加以下两行,以便应用程序正确编译。这也使得应用程序名称在iOS和Android上都实现了本地化,并在Android上设置了初始活动的标题。

    <string name="app_name">demo</string>
    <string name="title_activity_kimera">demo</string>
  • 有时,您可能需要完全从设备/模拟器中删除应用程序,以便插件完全工作(通常仅在插件在项目开发后期阶段安装时)。

  • 如果您在TypeScript中遇到关于L未定义的抱怨,那么请在您的references.d.ts中添加以下内容:/// <reference path="./node_modules/nativescript-i18n/references.d.ts" /> Nativescript i18n

JS文件

	console.log(L('home'));
console.log(L('multi_replace', 'ONE', 'TWO'));

Angular

如果您使用Angular来构建应用程序,那么事情会变得稍微复杂一些。

我的Angular技能为零,但@alejonext此评论中为此提供了一个解决方案。

更新 28.06.2016

@AirMike@loloof64 通过测试和进一步改进 @alejonext的PR,做了出色的工作,因此插件现在包括了Angular的支持:bow

在以常规方式将插件导入应用程序后,只需在您的文件(main.ts)中导入来自nativescript-i18n/angularNativeScriptI18nModule模块即可。

(请注意,以下说明是针对TypeScript而非纯JS)

	import { NativeScriptI18nModule } from "nativescript-i18n/angular";

然后在应用程序模块中导入它

	@NgModule({


imports: [
NativeScriptI18nModule
]


})
export class AppModule { }

Angular的使用方式为:{{ value | L:args }}

	<Button text="{{ 'Login' | L }}"></Button>

关于更详细的示例

您可以在main.ts中放入以下代码

    import { NativeScriptI18nModule } from 'nativescript-i18n/angular';

import { NativeScriptModule } from "nativescript-angular/platform";
import { NgModule } from "@angular/core";
import { AppComponent } from "./app.component";


@NgModule({

imports: [
NativeScriptModule,
NativeScriptI18nModule
],

declarations: [
AppComponent,
],
bootstrap: [AppComponent]
})
export class AppModule { }

对于主组件,假设以下HTML模板被使用(字符串定义见下文)

    <GridLayout rows="*,*,*">
<label row="0" text="{{'menuitem_new_file' | L }}"></label>
<label row="1" text="{{'menuitem_new_folder' | L }}"></label>
<label row="2" text="{{'menuitem_new' | L:'---':'***':124.25693 }}"></label>
</GridLayout>

以下是“en”的字符串定义(放入app/i18n/en/strings.xml中)

    <resources>
<string name="app_name">Chess Exercices Cupboard</string>
<string name="title_activity_kimera">Chess Exercices Cupboard</string>

<string formatted="false" name="menuitem_new">%s New... %s %0.2f</string>
<string name="menuitem_new_file">File</string>
<string name="menuitem_new_folder">Folder</string>
</resources>

以下是法语翻译(放入app/i18n/fr/srings.xml中)

    <resources>
<string name="app_name">Chess Exercices Cupboard</string>
<string name="title_activity_kimera">Chess Exercices Cupboard</string>

<string formatted="false" name="menuitem_new">%s Nouveau... %s %0.2f</string>
<string name="menuitem_new_file">Fichier</string>
<string name="menuitem_new_folder">Dossier</string>
</resources>

然后如果您的手机设置为法语,您会看到如下内容

    Fichier
Dossier
--- Nouveau... *** 124.25693

或者,如果设置为英语或“未识别”语言

    File
Folder
--- New... *** 124.25693

演示

请查看demo文件夹以获取一个工作示例。

iOS权限文本

将这些特殊键添加到app/i18n/(lang)/strings.xml中,用于在显示权限警报时通知用户,使用配置的语言。

键的说明
NSAppleMusicUsageDescription 指定您的应用程序使用媒体库的原因
NSBluetoothPeripheralUsageDescription 指定您的应用程序使用蓝牙的原因
NSCalendarsUsageDescription 指定您的应用程序访问用户日历的原因
NSCameraUsageDescription 指定您的应用程序访问设备摄像头的原因
NSContactsUsageDescription 指定您的应用程序访问用户联系人的原因
NSHealthShareUsageDescription 指定您的应用程序读取用户健康数据的原因
NSHealthUpdateUsageDescription 指定您的应用程序更改用户健康数据的原因
NSHomeKitUsageDescription 指定您的应用程序访问用户HomeKit配置数据的原因
NSLocationAlwaysUsageDescription 指定您的应用程序在所有时间访问用户位置信息的原因
NSLocationWhenInUseUsageDescription 指定您的应用程序在应用程序使用时访问用户位置信息的原因
NSMicrophoneUsageDescription 指定您的应用程序访问设备上任何麦克风的理由
NSMotionUsageDescription 指定您的应用程序访问设备加速度计的原因
NSPhotoLibraryUsageDescription 指定您的应用程序访问用户照片库的原因
NSRemindersUsageDescription 指定您的应用程序访问用户提醒的原因
NSSiriUsageDescription 指定您的应用程序向Siri发送用户数据的原因
NSSpeechRecognitionUsageDescription 指定您的应用向苹果的语音识别服务器发送用户数据的理由

(伪)路线图/想法

以下想法受到此评论以及本插件用户的帖子启发

  • [x] Android实现 - 使用App_Resources/Android/values/中的原生strings.xml
  • [x] iOS实现 - 使用原生Localizable.strings文件(这些文件需要放在哪里?)
  • [x] 允许格式化字符串,例如:L('hello', 'world')翻译为hello %s的定义(以及/或其他类型%d等)
  • [ ] 可能需要一个命令行工具/命令来从我们的语言功能使用中提取字符串并将它们放入我们的strings.xml进行翻译
  • [x] 将app/i18n中的strings.xml文件移动到正确位置(具体文件夹结构待定)并用作以下点的基准
    • [x] 在编译Android之前建立钩子以移动文件
    • [x] 在编译iOS之前建立钩子以翻译和移动文件
  • [ ] 关于资产(图片/启动屏幕等)怎么办?可能超出了此插件的范围
  • [x] 应用程序名称怎么办?
  • [ ] 我们是否需要一个模块级的缓存,这样我们就不必每次都跨越本地桥接?(应进行基准测试以决定此问题)
  • [x] 使缓存了解当前语言和语言更改
  • [x] Angular支持
  • [x] 语言文件的自定义路径(《https://github.com/rborn/nativescript-i18n/issues/28》#28)
  • [x] 设置应用程序的默认语言(《https://github.com/rborn/nativescript-i18n/issues/11》#11)
  • [x] 在iOS的应用程序权限提示中显示翻译(《https://github.com/rborn/nativescript-i18n/issues/45》#45)
  • [ ] 在某些文件无法创建的情况下报告错误
  • [ ] Webpack支持(《https://github.com/rborn/nativescript-i18n/issues/49》#49,《https://github.com/NativeScript/NativeScript/issues/42》#42)