# react-native: 共通文字列
URL: https://generaltranslation.com/ja/docs/react-native/guides/shared-strings.mdx
---
title: 共通文字列
description: 複数のコンポーネントやファイルで使われる文字列を国際化する方法
---
{/* 自動生成: 直接編集せず、代わりに content/docs-templates/ のテンプレートを編集してください。 */}
共通文字列とは、アプリケーション全体の複数箇所で使われるテキスト値のことです。たとえば、ナビゲーションラベル、フォームメッセージ、設定データなどです。各所で翻訳ロジックを重複して実装する代わりに、[`msg`](/docs/react-native/api/strings/msg)を使って文字列を翻訳対象としてマークし、[`useMessages`](/docs/react-native/api/strings/use-messages)でそれらをデコードします.
## 共通コンテンツの問題
アプリ全体で使われる、次のナビゲーション設定を考えてみましょう:
```tsx
// navData.ts
export const navData = [
{
label: 'Home',
description: 'The home page',
href: '/'
},
{
label: 'About',
description: 'Information about the company',
href: '/about'
}
];
```
これを国際化するには、通常は次の対応が必要になります。
1. 翻訳関数を受け取る関数に書き換える
2. すべての使用箇所を更新し、`t` を渡してその関数を呼び出す
3. そうした複雑さをコードベース全体で管理する
その結果、保守コストが増え、コードも読みにくくなります。[`msg`](/docs/react-native/api/strings/msg) 関数を使えば、文字列をその場で翻訳対象としてマークし、必要なときにデコードできるため、この問題を解決できます。
## クイックスタート
文字列のマークには [`msg`](/docs/react-native/api/strings/msg) を、デコードには [`useMessages`](/docs/react-native/api/strings/use-messages) を使用します。
```tsx
// navData.ts - 翻訳対象の文字列をマークする
import { msg } from 'gt-react-native';
export const navData = [
{
label: msg('Home'),
description: msg('The home page'),
href: '/'
},
{
label: msg('About'),
description: msg('Information about the company'),
href: '/about'
}
];
```
```tsx
// コンポーネントの使用 - マークされた文字列をデコードする
import { useMessages } from 'gt-react-native';
import { navData } from './navData';
function Navigation() {
const m = useMessages();
return (
);
}
```
## 共通文字列の仕組み
共通文字列システムは、次の 2 つのフェーズで動作します。
1. **Mark フェーズ**: [`msg`](/docs/react-native/api/strings/msg) は文字列に翻訳メタデータを付与してエンコードします
2. **Decode フェーズ**: [`useMessages`](/docs/react-native/api/strings/use-messages) は文字列をデコードして翻訳します
```tsx
// msg() は文字列をメタデータとともにエンコードする
const encoded = msg('Hello, world!');
console.log(encoded); // "Hello, world!:eyIkX2hhc2giOiJkMjA3MDliZGExNjNlZmM2In0="
// useMessages() はデコードして翻訳する
const m = useMessages();
const translated = m(encoded); // ユーザーの言語での "Hello, world!"
```
[`msg`](/docs/react-native/api/strings/msg) によるエンコード済みの文字列は直接使用できません。[`useMessages`](/docs/react-native/api/strings/use-messages) でデコードする必要があります。
## コンポーネント
[`useMessages`](/docs/react-native/api/strings/use-messages) フックを使います:
```tsx
import { useMessages } from 'gt-react-native';
const encodedString = msg('Hello, world!');
function MyComponent() {
const m = useMessages();
return
{m(encodedString)}
;
}
```
## decodeMsg で元の文字列を取得する
ログ出力、デバッグ、比較などで、翻訳前の元の文字列にアクセスしたい場合があります。元のテキストを取り出すには、[`decodeMsg`](/docs/react-native/api/strings/msg) を使用します。
```tsx
import { decodeMsg } from 'gt-react-native';
const encoded = msg('Hello, world!');
const original = decodeMsg(encoded); // "Hello, world!" (元の文字列)
const translated = m(encoded); // "Hello, world!" (ユーザーの言語)
// ログやデバッグに便利
console.log('Original string:', decodeMsg(encoded));
console.log('Translated string:', m(encoded));
```
### decodeMsgの用途
* **開発とデバッグ**: 問題の切り分けのために元の文字列をログ出力する
* **フォールバック処理**: 翻訳に失敗したときは元のテキストを使う
* **文字列の比較**: 既知の元の値と比較する
* **アナリティクス**: 元の文字列の使用状況を追跡する
```tsx
// 例: フォールバック処理
function getDisplayText(encodedStr) {
const m = useMessages();
try {
return m(encodedStr);
} catch (error) {
console.warn('翻訳に失敗しました。元の文字列を使用します:', decodeMsg(encodedStr));
return decodeMsg(encodedStr);
}
}
```
## 変数の使用
動的な内容を含む文字列では、プレースホルダーを使って変数を渡します:
```tsx
// 変数付きの文字列をマークする
const items = 100;
export const pricing = [
{
name: 'Basic',
price: 100,
description: msg('The basic plan includes {items} items', { items })
}
];
```
```tsx
// コンポーネントで使用
function PricingCard() {
const m = useMessages();
return (
{pricing[0].name}
{m(pricing[0].description)}
);
}
```
### ICU メッセージフォーマット
高度なフォーマットには、ICU 構文を使用します。
```tsx
const count = 10;
const message = msg('There are {count, plural, =0 {no items} =1 {one item} other {{count} items}} in the cart', { count });
```
ICU Message Format について詳しくは、[Unicode のドキュメント](https://unicode-org.github.io/icu/userguide/format_parse/messages/)を参照してください。
## 例
### ナビゲーション設定
```tsx
// config/navigation.ts
import { msg } from 'gt-react-native';
export const mainNav = [
{
label: msg('Home'),
href: '/',
icon: 'home'
},
{
label: msg('Products'),
href: '/products',
icon: 'package'
},
{
label: msg('About Us'),
href: '/about',
icon: 'info'
}
];
export const footerLinks = [
{
title: msg('Company'),
links: [
{ label: msg('About'), href: '/about' },
{ label: msg('Careers'), href: '/careers' },
{ label: msg('Contact'), href: '/contact' }
]
},
{
title: msg('Support'),
links: [
{ label: msg('Help Center'), href: '/help' },
{ label: msg('Documentation'), href: '/docs' },
{ label: msg('API Reference'), href: '/api' }
]
}
];
```
```tsx
// components/Navigation.tsx
import { useMessages } from 'gt-react-native';
import { mainNav } from '../config/navigation';
function Navigation() {
const m = useMessages();
return (
);
}
```
### フォームの設定
```tsx
// config/forms.ts
import { msg } from 'gt-react-native';
export const formMessages = {
placeholders: {
email: msg('Enter your email address'),
password: msg('Enter your password'),
message: msg('Type your message here...')
},
actions: {
send: msg('Send Message'),
save: msg('Save Changes'),
cancel: msg('Cancel')
},
validation: {
required: msg('This field is required'),
email: msg('Please enter a valid email address'),
minLength: msg('Must be at least {min} characters', { min: 8 }),
maxLength: msg('Cannot exceed {max} characters', { max: 100 })
},
success: {
saved: msg('Changes saved successfully'),
sent: msg('Message sent successfully'),
updated: msg('Profile updated')
},
errors: {
network: msg('Network error - please try again'),
server: msg('Server error - please contact support'),
timeout: msg('Request timed out - please try again')
}
};
```
```tsx
// components/ContactForm.tsx
import { useMessages } from 'gt-react-native';
import { formMessages } from '../config/forms';
function ContactForm() {
const m = useMessages();
const [errors, setErrors] = useState({});
return (
);
}
```
### 動的コンテンツの生成
```tsx
// utils/productData.ts
import { msg } from 'gt-react-native';
function mockProducts() {
return [
{ name: 'iPhone 15', company: 'Apple', category: 'Electronics' },
{ name: 'Galaxy S24', company: 'Samsung', category: 'Electronics' }
];
}
export function getProductData() {
const products = mockProducts();
return products.map(product => ({
...product,
description: msg('{name} is a {category} product by {company}', {
name: product.name,
category: product.category,
company: product.company
})
}));
}
```
```tsx
// components/ProductList.tsx
import { useMessages } from 'gt-react-native';
import { getProductData } from '../utils/productData';
function ProductList() {
const m = useMessages();
const products = getProductData();
return (
{products.map(product => (
{product.name}
{m(product.description)}
))}
);
}
```
## よくある問題
### エンコード済み文字列を直接使用する
[`msg`](/docs/react-native/api/strings/msg) の出力を直接使用しないでください。
```tsx
// ❌ 誤り - エンコードされた文字列を直接使用
const encoded = msg('Hello, world!');
return {encoded}
; // エンコードされた文字列が表示され、翻訳は表示されない
// ✅ 正しい - 先に文字列をデコードする
const encoded = msg('Hello, world!');
const m = useMessages();
return {m(encoded)}
; // 正しい翻訳が表示される
```
### msg() 内の動的なコンテンツ
文字列はビルド時点で確定している必要があります:
```tsx
// ❌ 誤り - 動的テンプレートリテラル
const name = 'John';
const message = msg(`Hello, ${name}`); // ビルド時エラー
// ✅ 正しい - 変数を使用する
const name = 'John';
const message = msg('Hello, {name}', { name });
```
### デコード忘れ
[`msg`](/docs/react-native/api/strings/msg) 文字列はすべてデコードする必要があります。
```tsx
// ❌ デコードが抜けている
const config = {
title: msg('Dashboard'),
subtitle: msg('Welcome back')
};
// コンポーネント内で後から使用する際にデコードを忘れた
return {config.title}
; // エンコードされた文字列が表示される
// ✅ 正しい方法 - 使用時にデコードする
const m = useMessages();
return {m(config.title)}
; // 翻訳されたタイトルが表示される
```
## 次のステップ
* [辞書ガイド](/docs/react-native/guides/dictionaries) - 構造化データで翻訳を整理する
* [言語ガイド](/docs/react-native/guides/languages) - サポートする言語を設定する
* API リファレンス:
* [`msg` 関数](/docs/react-native/api/strings/msg)